<?php

namespace App\Models;

use Carbon\CarbonImmutable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Validation\ValidationException;

class FinancialAccountTransaction extends Model
{
    protected $fillable = ['transaction_number','account_id','branch_id','transaction_date','reference','type','description','money_in','money_out','running_balance','user_id','transfer_id','related_type','related_id'];

    protected function casts(): array
    {
        return ['transaction_date'=>'datetime','money_in'=>'decimal:2','money_out'=>'decimal:2','running_balance'=>'decimal:2'];
    }

    protected static function booted(): void
    {
        static::creating(fn (FinancialAccountTransaction $transaction) => self::assertBooksOpen($transaction->branch_id, $transaction->transaction_date));
        static::updating(function (FinancialAccountTransaction $transaction): void {
            self::assertBooksOpen($transaction->branch_id, $transaction->transaction_date);
            if ($transaction->isDirty(['branch_id','transaction_date'])) {
                self::assertBooksOpen((int) $transaction->getOriginal('branch_id'), $transaction->getOriginal('transaction_date'));
            }
        });
        static::deleting(fn (FinancialAccountTransaction $transaction) => self::assertBooksOpen($transaction->branch_id, $transaction->transaction_date));
    }

    public function account(): BelongsTo { return $this->belongsTo(FinancialAccount::class, 'account_id'); }
    public function branch(): BelongsTo { return $this->belongsTo(Branch::class); }
    public function user(): BelongsTo { return $this->belongsTo(User::class); }
    public function transfer(): BelongsTo { return $this->belongsTo(FinancialTransfer::class, 'transfer_id'); }
    public function related(): MorphTo { return $this->morphTo(); }

    private static function assertBooksOpen(int|string|null $branchId, mixed $transactionDate): void
    {
        if (! $branchId || ! $transactionDate) return;
        $day = CarbonImmutable::parse($transactionDate)->startOfDay();
        $closedThrough = DailyClosing::query()
            ->where('branch_id', (int) $branchId)
            ->where('status', 'confirmed')
            ->max('closing_date');
        if ($closedThrough && $day->lte(CarbonImmutable::parse((string) $closedThrough)->startOfDay())) {
            throw ValidationException::withMessages([
                'transaction_date' => 'Financial books for this branch are closed through '.CarbonImmutable::parse((string) $closedThrough)->format('d M Y').'. Post the transaction on an open date.',
            ]);
        }
    }
}
