<?php

namespace App\Domain\Commissions\Models;

use App\Domain\Agents\Models\Agent;
use App\Domain\Commissions\Enums\SettlementStatus;
use App\Domain\Identity\Models\User;
use App\Support\Concerns\HasUuid;
use App\Support\Money\Money;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use RuntimeException;

/**
 * A period settlement for one agent (§13A).
 *
 * Gross, deductions and net are recomputed from the attached commissions on
 * every edit; the totals are never taken from the request.
 */
class AgentSettlement extends Model
{
    use HasUuid;

    protected $guarded = ['id', 'uuid'];

    protected function casts(): array
    {
        return [
            'status' => SettlementStatus::class,
            'period_start' => 'date',
            'period_end' => 'date',
            'gross_commission' => 'integer',
            'bonus_amount' => 'integer',
            'reversal_amount' => 'integer',
            'advance_deduction' => 'integer',
            'withholding_tax' => 'integer',
            'other_deduction' => 'integer',
            'net_payable' => 'integer',
            'approved_at' => 'datetime',
            'paid_at' => 'datetime',
        ];
    }

    protected static function booted(): void
    {
        static::updating(function (self $settlement) {
            if ($settlement->getOriginal('status') !== SettlementStatus::Paid) {
                return;
            }

            throw new RuntimeException('A paid settlement cannot be edited.');
        });

        static::deleting(fn () => throw new RuntimeException('Settlements cannot be deleted.'));
    }

    public function agent(): BelongsTo
    {
        return $this->belongsTo(Agent::class);
    }

    public function commissions(): HasMany
    {
        return $this->hasMany(Commission::class, 'agent_settlement_id');
    }

    public function approvedBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'approved_by');
    }

    public function net(): Money
    {
        return Money::of((int) $this->net_payable, $this->currency);
    }

    /** Total taken off the gross, for the statement (§13A ledger). */
    public function totalDeductions(): Money
    {
        return Money::of(
            (int) $this->advance_deduction + (int) $this->withholding_tax + (int) $this->other_deduction,
            $this->currency,
        );
    }
}
