<?php

namespace App\Livewire\Participants;

use App\Domain\Attendance\Models\AttendanceRecord;
use App\Domain\Financial\Models\Invoice;
use App\Domain\Financial\Services\PaymentService;
use App\Domain\Participant\Models\Participant;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\Locked;
use Livewire\Attributes\On;
use Livewire\Component;

class DeleteParticipant extends Component
{
    public bool $showModal = false;

    // Set by open() and by nothing else. Without the lock the browser could
    // swap it between opening the modal and confirming, so the refund and the
    // delete would land on a different player than the one on screen.
    #[Locked]
    public ?int $participantId = null;

    public ?string $participantName = null;

    public array $paidInvoices = [];
    public array $refundedInvoiceIds = [];
    public ?int $confirmingRefundInvoiceId = null;

    public bool $deleting = false;

    #[On('open-delete-participant')]
    public function open(int $id): void
    {
        $this->authorize('participants.delete');

        $participant = Participant::with('person')->findOrFail($id);
        $this->participantId = $id;
        $this->participantName = $participant->person?->name_ar ?? $participant->person?->name ?? '-';
        $this->refundedInvoiceIds = [];
        $this->confirmingRefundInvoiceId = null;
        $this->deleting = false;

        $this->loadInvoices();
        $this->showModal = true;
    }

    public function close(): void
    {
        $this->showModal = false;
        $this->reset(['participantId', 'participantName', 'paidInvoices', 'refundedInvoiceIds', 'confirmingRefundInvoiceId', 'deleting']);
    }

    private function loadInvoices(): void
    {
        $invoices = Invoice::where('billable_type', Participant::class)
            ->where('billable_id', $this->participantId)
            ->where('paid_amount', '>', 0)
            ->with(['payments', 'items'])
            ->orderByDesc('created_at')
            ->get();

        $this->paidInvoices = $invoices->map(fn ($inv) => [
            'id' => $inv->id,
            'number' => $inv->number,
            'total_amount' => $inv->total_amount,
            'paid_amount' => $inv->paid_amount,
            'status' => $inv->status->value ?? $inv->status,
            'issue_date' => $inv->issue_date?->format('Y-m-d'),
            'description' => $inv->items->first()?->description ?? '-',
        ])->toArray();
    }

    public function askRefund(int $invoiceId): void
    {
        $this->confirmingRefundInvoiceId = $invoiceId;
    }

    public function cancelRefund(): void
    {
        $this->confirmingRefundInvoiceId = null;
    }

    public function confirmRefund(int $invoiceId): void
    {
        $this->authorize('participants.delete');

        // The id comes from the modal's own list, so it is a browser value.
        // Invoice is branch-scoped now, which keeps another branch's money out
        // of reach, but nothing tied the invoice to the participant being
        // deleted — any invoice id in the branch was refundable from here.
        // Constrain it to the participant already in scope.
        $invoice = Invoice::where('billable_type', Participant::class)
            ->where('billable_id', $this->participantId)
            ->with('payments')
            ->findOrFail($invoiceId);
        $paymentService = app(PaymentService::class);

        DB::transaction(function () use ($invoice, $paymentService) {
            $confirmedPayments = $invoice->payments()
                ->where('direction', 'inbound')
                ->where('status', 'confirmed')
                ->get();

            foreach ($confirmedPayments as $payment) {
                $refundableAmount = $payment->amount;
                if ($refundableAmount > 0) {
                    $paymentService->refund($payment, $refundableAmount, auth()->user());
                }
            }
        });

        $this->refundedInvoiceIds[] = $invoiceId;
        $this->confirmingRefundInvoiceId = null;
        $this->loadInvoices();
    }

    public function deleteParticipant(): void
    {
        $this->authorize('participants.delete');
        $this->deleting = true;

        $participant = Participant::findOrFail($this->participantId);

        DB::transaction(function () use ($participant) {
            $participant->enrollments()
                ->whereIn('status', ['active', 'pending', 'waitlisted'])
                ->update(['status' => 'cancelled']);

            AttendanceRecord::where('subject_type', Participant::class)
                ->where('subject_id', $participant->id)
                ->where('status', 'expected')
                ->whereHas('session', fn ($q) => $q->where('session_date', '>=', now()->toDateString()))
                ->delete();

            Invoice::where('billable_type', Participant::class)
                ->where('billable_id', $participant->id)
                ->where('paid_amount', 0)
                ->whereIn('status', ['draft', 'sent'])
                ->update(['status' => 'cancelled', 'cancelled_at' => now()]);

            $participant->update(['status' => 'withdrawn']);
            $participant->delete();
        });

        $this->showModal = false;
        session()->flash('success', __('تم حذف المشترك بنجاح'));
        $this->redirect(route('participants.list'), navigate: true);
    }

    public function render()
    {
        return view('livewire.participants.delete-participant');
    }
}
