<?php

namespace App\Services;

use App\Enums\InvoiceStatus;
use App\Enums\QuotationStatus;
use App\Exceptions\DocumentException;
use App\Models\Invoice;
use App\Models\InvoiceItem;
use App\Models\Quotation;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class QuotationConversionService
{
    public function __construct(
        private readonly DocumentNumberService $documentNumbers,
        private readonly AuditService $audit,
    ) {}

    public function convert(Quotation $quotation): Invoice
    {
        return DB::transaction(function () use ($quotation): Invoice {
            $quotation = Quotation::query()
                ->with('items')
                ->lockForUpdate()
                ->findOrFail($quotation->id);

            if ($quotation->converted_invoice_id !== null) {
                throw new DocumentException('Quotation has already been converted to an invoice.');
            }

            if ($quotation->status !== QuotationStatus::Accepted) {
                throw new DocumentException('Only accepted quotations can be converted to invoices.');
            }

            $invoice = Invoice::query()->create([
                'invoice_number' => $this->documentNumbers->invoiceFromQuotation($quotation->quotation_number),
                'invoice_date' => now()->toDateString(),
                'due_date' => now()->addDays(30)->toDateString(),
                'quotation_id' => $quotation->id,
                'booking_id' => $quotation->booking_id,
                'customer_id' => $quotation->customer_id,
                'customer_snapshot' => $quotation->customer_snapshot,
                'event_snapshot' => $quotation->event_snapshot,
                'spaces_snapshot' => $quotation->spaces_snapshot,
                'guest_count' => $quotation->guest_count,
                'currency' => $quotation->currency,
                'subtotal' => $quotation->subtotal,
                'discount_amount' => $quotation->discount_amount,
                'service_charge_amount' => $quotation->service_charge_amount,
                'tax_amount' => $quotation->tax_amount,
                'grand_total' => $quotation->grand_total,
                'deposit_required' => $quotation->deposit_required,
                'amount_paid' => 0,
                'outstanding_balance' => $quotation->grand_total,
                'payment_terms' => $quotation->payment_terms,
                'notes' => $quotation->notes,
                'terms_and_conditions' => $quotation->terms_and_conditions,
                'status' => InvoiceStatus::Issued,
                'issued_at' => now(),
                'created_by' => Auth::id(),
            ]);

            foreach ($quotation->items as $item) {
                InvoiceItem::query()->create([
                    'invoice_id' => $invoice->id,
                    'description' => $item->description,
                    'quantity' => $item->quantity,
                    'unit_price' => $item->unit_price,
                    'charge_basis' => $item->charge_basis,
                    'guest_count' => $item->guest_count,
                    'billable_days' => $item->billable_days,
                    'billable_hours' => $item->billable_hours,
                    'discount_amount' => $item->discount_amount,
                    'tax_rate' => $item->tax_rate,
                    'tax_amount' => $item->tax_amount,
                    'line_total' => $item->line_total,
                    'product_id' => $item->product_id,
                    'package_id' => $item->package_id,
                    'product_snapshot' => $item->product_snapshot,
                    'package_snapshot' => $item->package_snapshot,
                    'sort_order' => $item->sort_order,
                ]);
            }

            $quotation->update([
                'status' => QuotationStatus::Converted,
                'converted_invoice_id' => $invoice->id,
            ]);

            $this->audit->log('quotation.converted', $quotation, null, [
                'invoice_id' => $invoice->id,
                'invoice_number' => $invoice->invoice_number,
                'booking_id' => $quotation->booking_id,
            ]);

            return $invoice->fresh(['items', 'customer', 'booking', 'quotation']);
        });
    }
}
