<?php

namespace App\Services\Billing;

use App\Models\InvoiceItemModel;
use App\Models\InvoiceModel;
use Config\Database;

class InvoiceService
{
    private InvoiceModel $invoices;
    private InvoiceItemModel $items;

    public function __construct()
    {
        $this->invoices = new InvoiceModel();
        $this->items    = new InvoiceItemModel();
    }

    /**
     * @param array<int, array{description:string, quantity:int, unit_price:float}> $lineItems
     */
    public function generate(int $agencyId, array $lineItems, ?string $dueDate = null): array
    {
        $subtotal = array_sum(array_map(fn ($i) => $i['quantity'] * $i['unit_price'], $lineItems));

        $taxPercentage = (float) (Database::connect()->table('settings')
            ->where('group', 'payment')->where('key', 'tax_percentage')
            ->get()->getRow()->value ?? 0);

        $taxAmount = round($subtotal * ($taxPercentage / 100), 2);
        $total = round($subtotal + $taxAmount, 2);

        $invoiceId = $this->invoices->insert([
            'agency_id'      => $agencyId,
            'invoice_number' => $this->invoices->nextInvoiceNumber(),
            'subtotal'       => $subtotal,
            'tax_percentage' => $taxPercentage,
            'tax_amount'     => $taxAmount,
            'total'          => $total,
            'status'         => 'sent',
            'due_date'       => $dueDate ?? date('Y-m-d', strtotime('+7 days')),
            'created_at'     => date('Y-m-d H:i:s'),
        ], true);

        foreach ($lineItems as $item) {
            $this->items->insert([
                'invoice_id'  => $invoiceId,
                'description' => $item['description'],
                'quantity'    => $item['quantity'],
                'unit_price'  => $item['unit_price'],
                'line_total'  => round($item['quantity'] * $item['unit_price'], 2),
            ]);
        }

        return $this->getWithItems($invoiceId);
    }

    public function markPaid(int $invoiceId): void
    {
        $this->invoices->update($invoiceId, ['status' => 'paid']);
    }

    public function getWithItems(int $invoiceId): array
    {
        $invoice = $this->invoices->find($invoiceId);
        return ['invoice' => $invoice, 'items' => $this->items->forInvoice($invoiceId)];
    }

    public function forAgency(int $agencyId, int $page = 1, int $perPage = 20): array
    {
        return $this->invoices->forAgency($agencyId, $page, $perPage);
    }

    /**
     * Renders and stores the invoice PDF. Uses the pdf skill's dompdf
     * pattern rather than a bespoke renderer — kept as a thin wrapper so
     * the actual HTML template lives in a view (invoices/pdf_template.php)
     * for easy branding edits.
     */
    public function generatePdf(int $invoiceId): string
    {
        if (! class_exists(\Dompdf\Dompdf::class)) {
            throw new \RuntimeException(
                'PDF generation requires the dompdf/dompdf package, which is not installed in this deployment. ' .
                'If you have Composer access, run: composer require dompdf/dompdf'
            );
        }

        $data = $this->getWithItems($invoiceId);

        $html = view('billing/invoice_pdf', $data);

        $dompdf = new \Dompdf\Dompdf();
        $dompdf->loadHtml($html);
        $dompdf->setPaper('A4');
        $dompdf->render();

        $dir = WRITEPATH . 'uploads/invoices';
        if (! is_dir($dir)) {
            mkdir($dir, 0755, true);
        }

        $filename = $data['invoice']['invoice_number'] . '.pdf';
        $path = $dir . '/' . $filename;
        file_put_contents($path, $dompdf->output());

        $this->invoices->update($invoiceId, ['pdf_path' => 'uploads/invoices/' . $filename]);

        return $path;
    }
}
