<?php

namespace App\Livewire\Admin;

use App\Domain\Financial\Enums\InvoiceStatus;
use App\Domain\Financial\Models\Invoice;
use App\Domain\Financial\Models\Payment;
use App\Domain\Financial\Services\InvoiceService;
use App\Domain\Financial\Services\PaymentService;
use App\Domain\Participant\Models\Participant;
use App\Domain\Shared\Exceptions\DomainException;
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 InvoiceCorrectionWizard extends Component
{
    public int $currentStep = 1;

    // Step 1: Find participant
    public string $search = '';
    public ?int $selectedParticipantId = null;
    public string $selectedParticipantName = '';

    // Step 2: Select invoice
    public ?int $selectedInvoiceId = null;
    public array $invoiceDetails = [];

    // Step 3: Correction details
    public string $correctionType = 'adjust_amount'; // adjust_amount | split_installment | change_description
    public string $newAmountInput = '';
    public string $newDescription = '';
    public string $correctionReason = '';
    public bool $createRemainderInvoice = true;
    public string $remainderDueDate = '';
    public string $remainderDescription = '';

    // Step 4: Results
    public bool $completed = false;
    public array $correctionResult = [];

    public function mount(): void
    {
        $this->authorize('super_admin.access');
        $this->remainderDueDate = now()->addMonth()->startOfMonth()->toDateString();
    }

    public function selectParticipant(int $id, string $name): void
    {
        $this->selectedParticipantId = $id;
        $this->selectedParticipantName = $name;
        $this->search = '';
        $this->currentStep = 2;
    }

    public function selectInvoice(int $invoiceId): void
    {
        $invoice = Invoice::with('items', 'payments')->find($invoiceId);
        if (!$invoice) {
            return;
        }

        $this->selectedInvoiceId = $invoiceId;
        $this->invoiceDetails = [
            'id' => $invoice->id,
            'number' => $invoice->number,
            'status' => $invoice->status->value,
            'total_amount' => $invoice->total_amount,
            'paid_amount' => $invoice->paid_amount,
            'due_amount' => $invoice->due_amount,
            'notes' => $invoice->notes,
            'issue_date' => $invoice->issue_date?->format('Y-m-d'),
            'items' => $invoice->items->map(fn ($item) => [
                'id' => $item->id,
                'description' => $item->description,
                'unit_price' => $item->unit_price,
                'quantity' => $item->quantity,
                'total_amount' => $item->total_amount,
            ])->toArray(),
            'payments' => $invoice->payments->map(fn ($p) => [
                'id' => $p->id,
                'amount' => $p->amount,
                'method' => $p->method,
                'payment_date' => $p->payment_date,
                'status' => $p->status,
            ])->toArray(),
        ];

        $this->newAmountInput = number_format($invoice->total_amount / 100, 2, '.', '');
        $this->newDescription = $invoice->items->first()?->description ?? '';
        $this->currentStep = 3;
    }

    public function previousStep(): void
    {
        if ($this->currentStep === 3) {
            $this->selectedInvoiceId = null;
            $this->invoiceDetails = [];
            $this->currentStep = 2;
        } elseif ($this->currentStep === 2) {
            $this->selectedParticipantId = null;
            $this->selectedParticipantName = '';
            $this->currentStep = 1;
        }
    }

    public function getNewAmountPiastersProperty(): int
    {
        return max(0, (int) round((float) $this->newAmountInput * 100));
    }

    public function getOriginalAmountProperty(): int
    {
        return $this->invoiceDetails['total_amount'] ?? 0;
    }

    public function getDifferenceProperty(): int
    {
        return $this->originalAmount - $this->newAmountPiasters;
    }

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

        $this->validate([
            'correctionReason' => 'required|min:10',
            'newAmountInput' => 'required|numeric|min:0',
        ], [
            'correctionReason.required' => 'سبب التصحيح مطلوب',
            'correctionReason.min' => 'سبب التصحيح يجب أن يكون 10 أحرف على الأقل',
            'newAmountInput.required' => 'المبلغ الجديد مطلوب',
            'newAmountInput.numeric' => 'المبلغ يجب أن يكون رقم',
            'newAmountInput.min' => 'المبلغ لا يمكن أن يكون سالب',
        ]);

        $actor = auth()->user();
        $invoice = Invoice::with('items', 'payments')->find($this->selectedInvoiceId);

        if (!$invoice) {
            session()->flash('error', 'الفاتورة غير موجودة');
            return;
        }

        $newAmount = $this->newAmountPiasters;
        $originalAmount = $invoice->total_amount;
        $difference = $originalAmount - $newAmount;

        if ($newAmount === $originalAmount && $this->correctionType !== 'change_description') {
            session()->flash('error', 'المبلغ الجديد مطابق للمبلغ الأصلي');
            return;
        }

        try {
            $result = DB::transaction(function () use ($invoice, $actor, $newAmount, $originalAmount, $difference) {
                $oldData = [
                    'total_amount' => $invoice->total_amount,
                    'subtotal_amount' => $invoice->subtotal_amount,
                    'paid_amount' => $invoice->paid_amount,
                    'due_amount' => $invoice->due_amount,
                    'status' => $invoice->status->value,
                    'notes' => $invoice->notes,
                    'items' => $invoice->items->toArray(),
                ];

                $invoiceService = app(InvoiceService::class);
                $remainderInvoice = null;

                // Adjust the invoice amount
                $invoice->subtotal_amount = $newAmount;
                $invoice->total_amount = $newAmount;

                // Adjust payments if they exceed new amount
                if ($invoice->paid_amount > $newAmount) {
                    $invoice->paid_amount = $newAmount;
                }

                $invoice->due_amount = max(0, $newAmount - $invoice->paid_amount);

                // Update status based on new amounts
                if ($invoice->due_amount === 0 && $newAmount > 0) {
                    $invoice->status = InvoiceStatus::Paid;
                    $invoice->paid_at = $invoice->paid_at ?? now();
                } elseif ($invoice->paid_amount > 0 && $invoice->due_amount > 0) {
                    $invoice->status = InvoiceStatus::PartiallyPaid;
                } elseif ($newAmount === 0) {
                    $invoice->status = InvoiceStatus::Cancelled;
                    $invoice->cancelled_at = now();
                }

                // Update notes
                $correctionNote = 'تصحيح: ' . $this->correctionReason;
                $invoice->notes = $correctionNote;

                // Update metadata with audit trail
                $invoice->metadata = array_merge($invoice->metadata ?? [], [
                    'correction' => [
                        'corrected_at' => now()->toIso8601String(),
                        'corrected_by' => $actor->id,
                        'corrected_by_name' => $actor->name,
                        'original_amount' => $originalAmount,
                        'new_amount' => $newAmount,
                        'difference' => $difference,
                        'reason' => $this->correctionReason,
                        'type' => $this->correctionType,
                    ],
                ]);

                $invoice->save();

                // Update invoice items
                $mainItem = $invoice->items->first();
                if ($mainItem) {
                    $mainItem->update([
                        'unit_price' => $newAmount,
                        'total_amount' => $newAmount,
                        'description' => $this->newDescription ?: $mainItem->description,
                    ]);
                }

                // Fix payment amounts if they exceeded the new total
                foreach ($invoice->payments as $payment) {
                    if ($payment->amount > $newAmount) {
                        $payment->update(['amount' => $newAmount]);
                    }
                }

                // Create remainder invoice if needed
                if ($this->createRemainderInvoice && $difference > 0) {
                    $participant = Participant::with('person')->find($this->selectedParticipantId);

                    $remainderInvoice = $invoiceService->create([
                        'academy_id' => $invoice->academy_id,
                        'billable_type' => $invoice->billable_type,
                        'billable_id' => $invoice->billable_id,
                        'total_amount' => $difference,
                        'subtotal_amount' => $difference,
                        'discount_amount' => 0,
                        'tax_amount' => 0,
                        'service_fee_amount' => 0,
                        'due_date' => $this->remainderDueDate,
                        'contact_name' => $participant?->person?->name_ar ?? $invoice->contact_name,
                        'notes' => $this->remainderDescription ?: ('أقساط متبقية — تصحيح من ' . $invoice->number),
                        'metadata' => [
                            'correction_remainder' => true,
                            'original_invoice_id' => $invoice->id,
                            'original_invoice_number' => $invoice->number,
                            'corrected_at' => now()->toIso8601String(),
                        ],
                    ], [
                        [
                            'description' => $this->remainderDescription ?: ('المبلغ المتبقي من ' . $invoice->number),
                            'quantity' => 1,
                            'unit_price' => $difference,
                            'discount_amount' => 0,
                            'tax_amount' => 0,
                        ],
                    ], $actor);

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

                // Audit log
                Log::channel('audit')->info('invoice_correction', [
                    'actor_id' => $actor->id,
                    'actor_name' => $actor->name,
                    'invoice_id' => $invoice->id,
                    'invoice_number' => $invoice->number,
                    'participant_id' => $this->selectedParticipantId,
                    'participant_name' => $this->selectedParticipantName,
                    'correction_type' => $this->correctionType,
                    'original_amount' => $originalAmount,
                    'new_amount' => $newAmount,
                    'difference' => $difference,
                    'reason' => $this->correctionReason,
                    'remainder_invoice_id' => $remainderInvoice?->id,
                    'remainder_invoice_number' => $remainderInvoice?->number,
                    'old_data' => $oldData,
                    'timestamp' => now()->toIso8601String(),
                ]);

                return [
                    'invoice_number' => $invoice->number,
                    'original_amount' => $originalAmount,
                    'new_amount' => $newAmount,
                    'new_status' => $invoice->status->value,
                    'remainder_invoice' => $remainderInvoice ? [
                        'number' => $remainderInvoice->number,
                        'amount' => $difference,
                    ] : null,
                ];
            });

            $this->correctionResult = $result;
            $this->completed = true;
            $this->currentStep = 4;

        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        } catch (\Throwable $e) {
            Log::error('Invoice correction failed', [
                'invoice_id' => $this->selectedInvoiceId,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);
            session()->flash('error', 'حدث خطأ: ' . $e->getMessage());
        }
    }

    public function startOver(): void
    {
        $this->reset();
        $this->remainderDueDate = now()->addMonth()->startOfMonth()->toDateString();
        $this->currentStep = 1;
    }

    public function render()
    {
        $searchResults = collect();
        if (strlen($this->search) >= 2 && !$this->selectedParticipantId) {
            $searchResults = Participant::query()
                ->with('person')
                ->where(function ($q) {
                    $search = $this->search;
                    $q->where('participant_number', 'ilike', "%{$search}%")
                      ->orWhereHas('person', function ($pq) use ($search) {
                          $pq->where('name_ar', 'ilike', "%{$search}%")
                             ->orWhere('name', 'ilike', "%{$search}%")
                             ->orWhere('phone', 'like', "%{$search}%");
                      });
                })
                ->limit(10)
                ->get();
        }

        $invoices = collect();
        if ($this->selectedParticipantId && $this->currentStep === 2) {
            $invoices = Invoice::where('billable_id', $this->selectedParticipantId)
                ->where('billable_type', 'App\\Domain\\Participant\\Models\\Participant')
                ->with('items')
                ->orderByDesc('created_at')
                ->get();
        }

        return view('livewire.admin.invoice-correction-wizard', [
            'searchResults' => $searchResults,
            'invoices' => $invoices,
        ]);
    }
}
