<?php

namespace App\Observers;

use App\Models\Payment;
use App\Models\Contract;
use App\Models\PaymentScheduleItem;

class PaymentObserver
{
    private static bool $handlingSurplus = false;

    /**
     * Tính toán lại tài chính hợp đồng sau mỗi thay đổi payment.
     */
    private function recalculateContract(Contract $contract): void
    {
        $totalPaid = (float) $contract->payments()->sum('amount');
        $contractValue = (float) $contract->total_value;

        $contract->paid_amount = $totalPaid;

        if ($totalPaid > $contractValue) {
            $contract->remaining_amount = 0;
            $contract->excess_amount = $totalPaid - $contractValue;
        } else {
            $contract->remaining_amount = $contractValue - $totalPaid;
            $contract->excess_amount = 0;
        }

        $contract->saveQuietly();
    }

    /**
     * Tự động khấu trừ tiền dư vào đợt thanh toán tiếp theo.
     */
    private function applySurplusToNextInstallment(Contract $contract): void
    {
        if (self::$handlingSurplus) {
            return;
        }

        $excess = (float) $contract->excess_amount;
        if ($excess <= 0) {
            return;
        }

        // Tìm đợt tiếp theo chưa thanh toán đủ (hoặc chưa có payment nào)
        $nextItem = PaymentScheduleItem::query()
            ->whereHas('schedule', fn ($q) => $q->where('contract_id', $contract->id))
            ->whereNotNull('amount')
            ->orderBy('installment_no')
            ->get()
            ->first(function ($item) use ($contract) {
                $paidForItem = (float) $contract->payments()
                    ->where('schedule_item_id', $item->id)
                    ->sum('amount');
                return $paidForItem < (float) $item->amount;
            });

        if (! $nextItem) {
            return;
        }

        $paidForItem = (float) $contract->payments()
            ->where('schedule_item_id', $nextItem->id)
            ->sum('amount');
        $remainingForItem = (float) $nextItem->amount - $paidForItem;

        if ($remainingForItem <= 0) {
            return;
        }

        $applyAmount = min($excess, $remainingForItem);

        self::$handlingSurplus = true;

        Payment::create([
            'contract_id' => $contract->id,
            'schedule_item_id' => $nextItem->id,
            'amount' => $applyAmount,
            'paid_date' => now(),
            'method' => 'Tự động khấu trừ',
            'receipt_number' => 'AUTO-SURPLUS-' . now()->format('YmdHis'),
            'metadata' => ['auto_surplus' => true, 'source' => 'excess_amount'],
        ]);

        self::$handlingSurplus = false;
    }

    public function created(Payment $payment): void
    {
        if ($payment->contract) {
            $this->recalculateContract($payment->contract);
            $this->applySurplusToNextInstallment($payment->contract);
        }
    }

    public function updated(Payment $payment): void
    {
        if ($payment->contract) {
            $this->recalculateContract($payment->contract);
            $this->applySurplusToNextInstallment($payment->contract);
        }

        if ($payment->wasChanged('contract_id') && $payment->getOriginal('contract_id')) {
            $oldContract = Contract::find($payment->getOriginal('contract_id'));
            if ($oldContract) {
                $this->recalculateContract($oldContract);
            }
        }
    }

    public function deleted(Payment $payment): void
    {
        if ($payment->contract) {
            $this->recalculateContract($payment->contract);
        }
    }
}
