<?php

namespace App\Livewire\Admin;

use App\Domain\Financial\Enums\InvoiceStatus;
use App\Domain\Financial\Models\Invoice;
use App\Domain\Financial\Services\InvoiceService;
use App\Domain\Financial\Services\PaymentService;
use App\Domain\Participant\Models\Participant;
use App\Domain\Pricing\Services\PricingService;
use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Training\Enums\EnrollmentStatus;
use App\Domain\Training\Models\Enrollment;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('تسوية المشتركين')]
class ReconciliationWizard extends Component
{
    public int $currentStep = 1;

    // Step 1: list of participants with zero invoices
    public array $selectedParticipantIds = [];

    // Step 2: per-participant config
    public ?int $activeParticipantId = null;
    public array $participantConfigs = [];
    // config structure: [participant_id => ['mode' => 'two_invoices'|'one_invoice', 'pay_now' => bool, 'payment_method' => 'cash']]

    // Step 3: results
    public array $results = [];
    public bool $completed = false;

    public function mount(): void
    {
        $this->authorize('super_admin.access');
    }

    public function selectAll(array $ids): void
    {
        $this->selectedParticipantIds = $ids;
    }

    public function toggleParticipant(int $id): void
    {
        if (in_array($id, $this->selectedParticipantIds)) {
            $this->selectedParticipantIds = array_values(array_diff($this->selectedParticipantIds, [$id]));
        } else {
            $this->selectedParticipantIds[] = $id;
        }
    }

    public function proceedToConfig(): void
    {
        if (empty($this->selectedParticipantIds)) {
            session()->flash('error', __('يرجى اختيار مشترك واحد على الأقل'));
            return;
        }

        foreach ($this->selectedParticipantIds as $id) {
            if (!isset($this->participantConfigs[$id])) {
                $this->participantConfigs[$id] = [
                    'mode' => 'two_invoices',
                    'pay_now' => true,
                    'payment_method' => 'cash',
                ];
            }
        }

        $this->activeParticipantId = $this->selectedParticipantIds[0];
        $this->currentStep = 2;
    }

    public function setActiveParticipant(int $id): void
    {
        $this->activeParticipantId = $id;
    }

    public function applyToAll(string $mode, bool $payNow, string $method): void
    {
        foreach ($this->selectedParticipantIds as $id) {
            $this->participantConfigs[$id] = [
                'mode' => $mode,
                'pay_now' => $payNow,
                'payment_method' => $method,
            ];
        }
    }

    public function executeReconciliation(InvoiceService $invoiceService, PaymentService $paymentService, PricingService $pricingService): void
    {
        $this->authorize('super_admin.access');
        $this->results = [];
        $actor = auth()->user();

        foreach ($this->selectedParticipantIds as $participantId) {
            $config = $this->participantConfigs[$participantId] ?? ['mode' => 'two_invoices', 'pay_now' => true, 'payment_method' => 'cash'];

            try {
                $result = DB::transaction(function () use ($participantId, $config, $invoiceService, $paymentService, $pricingService, $actor) {
                    $participant = Participant::with('person')->find($participantId);
                    if (!$participant) {
                        throw new DomainException('المشترك غير موجود');
                    }

                    $enrollments = Enrollment::where('participant_id', $participantId)
                        ->where('status', EnrollmentStatus::Active)
                        ->with(['program', 'group'])
                        ->get();

                    $invoicesCreated = [];

                    foreach ($enrollments as $enrollment) {
                        $program = $enrollment->program;
                        if (!$program) {
                            continue;
                        }

                        $branchId = $enrollment->group?->branch_id ?? $participant->branch_id;

                        try {
                            $priceResult = $pricingService->calculate(
                                priceable: $program,
                                participant: $participant,
                                branchId: $branchId,
                            );
                        } catch (DomainException $e) {
                            continue;
                        }

                        if ($priceResult->finalAmount <= 0) {
                            continue;
                        }

                        if ($config['mode'] === 'two_invoices') {
                            // Invoice 1: last month (already paid offline)
                            $lastMonthInvoice = $invoiceService->create([
                                'academy_id' => $enrollment->academy_id,
                                'branch_id' => $branchId,
                                'billable_type' => $participant->getMorphClass(),
                                'billable_id' => $participant->id,
                                'total_amount' => $priceResult->finalAmount,
                                'subtotal_amount' => $priceResult->baseAmount,
                                'discount_amount' => $priceResult->totalDiscount,
                                'tax_amount' => 0,
                                'issue_date' => now()->subMonth()->startOfMonth()->toDateString(),
                                'due_date' => now()->subMonth()->endOfMonth()->toDateString(),
                                'contact_name' => $participant->person?->name_ar,
                                'notes' => 'تسوية — اشتراك الشهر السابق: ' . $program->name_ar,
                            ], [
                                [
                                    'description' => "اشتراك الشهر السابق: {$program->name_ar}",
                                    'quantity' => 1,
                                    'unit_price' => $priceResult->baseAmount,
                                    'discount_amount' => $priceResult->totalDiscount,
                                    'tax_amount' => 0,
                                ],
                            ], $actor);

                            $lastMonthInvoice->update(['status' => InvoiceStatus::Sent]);

                            // Record payment for last month (paid offline)
                            $paymentService->recordPayment([
                                'invoice_id' => $lastMonthInvoice->id,
                                'branch_id' => $branchId,
                                'amount' => $lastMonthInvoice->total_amount,
                                'method' => $config['payment_method'],
                                'direction' => 'inbound',
                                'currency' => 'EGP',
                                'payment_date' => now()->subMonth()->toDateString(),
                                'notes' => 'تسوية — دفع سابق خارج النظام',
                            ], $actor);

                            $invoicesCreated[] = ['invoice' => $lastMonthInvoice->fresh(), 'label' => 'الشهر السابق'];

                            // Invoice 2: current month renewal
                            $currentInvoice = $invoiceService->create([
                                'academy_id' => $enrollment->academy_id,
                                'branch_id' => $branchId,
                                'billable_type' => $participant->getMorphClass(),
                                'billable_id' => $participant->id,
                                'total_amount' => $priceResult->finalAmount,
                                'subtotal_amount' => $priceResult->baseAmount,
                                'discount_amount' => $priceResult->totalDiscount,
                                'tax_amount' => 0,
                                'due_date' => now()->addDays(7)->toDateString(),
                                'contact_name' => $participant->person?->name_ar,
                                'notes' => 'تجديد اشتراك — ' . $program->name_ar,
                            ], [
                                [
                                    'description' => "تجديد اشتراك: {$program->name_ar}",
                                    'quantity' => 1,
                                    'unit_price' => $priceResult->baseAmount,
                                    'discount_amount' => $priceResult->totalDiscount,
                                    'tax_amount' => 0,
                                ],
                            ], $actor);

                            $currentInvoice->update(['status' => InvoiceStatus::Sent]);

                            if ($config['pay_now']) {
                                $paymentService->recordPayment([
                                    'invoice_id' => $currentInvoice->id,
                                    'branch_id' => $branchId,
                                    'amount' => $currentInvoice->total_amount,
                                    'method' => $config['payment_method'],
                                    'direction' => 'inbound',
                                    'currency' => 'EGP',
                                    'payment_date' => now()->toDateString(),
                                    'notes' => 'تسوية — دفع تجديد الشهر الحالي',
                                ], $actor);
                            }

                            $invoicesCreated[] = ['invoice' => $currentInvoice->fresh(), 'label' => 'الشهر الحالي'];

                        } else {
                            // One combined invoice for everything
                            $totalAmount = $priceResult->finalAmount * 2; // last month + current
                            $invoice = $invoiceService->create([
                                'academy_id' => $enrollment->academy_id,
                                'branch_id' => $branchId,
                                'billable_type' => $participant->getMorphClass(),
                                'billable_id' => $participant->id,
                                'total_amount' => $totalAmount,
                                'subtotal_amount' => $priceResult->baseAmount * 2,
                                'discount_amount' => $priceResult->totalDiscount * 2,
                                'tax_amount' => 0,
                                'due_date' => now()->addDays(7)->toDateString(),
                                'contact_name' => $participant->person?->name_ar,
                                'notes' => 'تسوية — اشتراك شهرين: ' . $program->name_ar,
                            ], [
                                [
                                    'description' => "اشتراك الشهر السابق: {$program->name_ar}",
                                    'quantity' => 1,
                                    'unit_price' => $priceResult->baseAmount,
                                    'discount_amount' => $priceResult->totalDiscount,
                                    'tax_amount' => 0,
                                ],
                                [
                                    'description' => "تجديد الشهر الحالي: {$program->name_ar}",
                                    'quantity' => 1,
                                    'unit_price' => $priceResult->baseAmount,
                                    'discount_amount' => $priceResult->totalDiscount,
                                    'tax_amount' => 0,
                                ],
                            ], $actor);

                            $invoice->update(['status' => InvoiceStatus::Sent]);

                            if ($config['pay_now']) {
                                $paymentService->recordPayment([
                                    'invoice_id' => $invoice->id,
                                    'branch_id' => $branchId,
                                    'amount' => $invoice->total_amount,
                                    'method' => $config['payment_method'],
                                    'direction' => 'inbound',
                                    'currency' => 'EGP',
                                    'payment_date' => now()->toDateString(),
                                    'notes' => 'تسوية — دفع كامل لشهرين',
                                ], $actor);
                            }

                            $invoicesCreated[] = ['invoice' => $invoice->fresh(), 'label' => 'فاتورة موحدة'];
                        }

                        // Advance billing date so they're in the normal cycle going forward
                        $this->advanceBillingDate($enrollment);
                    }

                    return [
                        'participant_id' => $participantId,
                        'name' => $participant->person?->name_ar ?? '-',
                        'status' => 'success',
                        'invoices' => count($invoicesCreated),
                        'message' => 'تمت التسوية بنجاح',
                    ];
                });

                $this->results[] = $result;

            } catch (\Throwable $e) {
                Log::error('Reconciliation failed', ['participant_id' => $participantId, 'error' => $e->getMessage()]);
                $this->results[] = [
                    'participant_id' => $participantId,
                    'name' => Participant::with('person')->find($participantId)?->person?->name_ar ?? '-',
                    'status' => 'error',
                    'invoices' => 0,
                    'message' => $e->getMessage(),
                ];
            }
        }

        $this->completed = true;
        $this->currentStep = 3;
    }

    private function advanceBillingDate(Enrollment $enrollment): void
    {
        $program = $enrollment->program;
        $billingDay = $program->billing_day ?? 1;

        $next = now()->addMonth();
        $maxDay = $next->daysInMonth;
        $next->day = min($billingDay, $maxDay);

        $enrollment->update([
            'next_billing_date' => $next->toDateString(),
            'last_billed_at' => now()->toDateString(),
            'payment_status' => 'current',
        ]);
    }

    public function render()
    {
        $unpaidParticipants = collect();

        if ($this->currentStep === 1) {
            // Find participants who are enrolled (active) but have ZERO invoices in the system
            $unpaidParticipants = Participant::query()
                ->whereHas('enrollments', fn ($q) => $q->where('status', EnrollmentStatus::Active))
                ->whereDoesntHave('invoices')
                ->with(['person', 'enrollments' => fn ($q) => $q->where('status', 'active')->with('program')])
                ->orderBy('id')
                ->get();
        }

        $configParticipants = collect();
        if ($this->currentStep === 2) {
            $configParticipants = Participant::whereIn('id', $this->selectedParticipantIds)
                ->with(['person', 'enrollments' => fn ($q) => $q->where('status', 'active')->with('program')])
                ->get()
                ->keyBy('id');
        }

        return view('livewire.admin.reconciliation-wizard', [
            'unpaidParticipants' => $unpaidParticipants,
            'configParticipants' => $configParticipants,
        ]);
    }
}
