<?php
declare(strict_types=1);

namespace App\Controllers\Web;

use App\Middleware\AuthSession;
use App\Middleware\TenantScope;
use App\Models\Customer;
use App\Models\ProductService;
use App\Models\Quote;
use App\Models\Tenant;
use App\Lib\Pdf;
use Core\Controller;
use Core\Session;
use Core\Tool;

final class QuotesController extends Controller
{
    public function middleware(): array
    {
        return [AuthSession::class, TenantScope::class];
    }

    private function tenantId(): int
    {
        return (int) ($_SESSION['tenant_id'] ?? 0);
    }

    private function userId(): int
    {
        return (int) (Session::user()['user_id'] ?? 0);
    }

    public function index(): void
    {
        $filters = [
            'status'      => $_GET['status']      ?? null,
            'customer_id' => $_GET['customer_id'] ?? null,
            'q'           => $_GET['q']           ?? null,
        ];
        $sort      = $_GET['sort'] ?? 'newest';
        $tenantId  = $this->tenantId();
        $active    = array_filter($filters);
        $perPage   = (int) ($_GET['per_page'] ?? 25);
        $perPage   = max(10, min($perPage, 100));
        $page      = max(1, (int) ($_GET['page'] ?? 1));
        $total     = Quote::countForTenant($tenantId, $active);
        $lastPage  = max(1, (int) ceil($total / $perPage));
        if ($page > $lastPage) $page = $lastPage;

        $this->render('quotes/index', [
            'quotes'    => Quote::listForTenant($tenantId, $active, $perPage, ($page - 1) * $perPage, $sort),
            'sort'      => $sort,
            'filters'   => $filters,
            'customers' => Customer::optionsForTenant($tenantId),
            'flash'     => Session::flash('quote_msg'),
            'pager'     => [
                'total'    => $total,
                'per_page' => $perPage,
                'page'     => $page,
                'last'     => $lastPage,
                'from'     => $total > 0 ? ($page - 1) * $perPage + 1 : 0,
                'to'       => min($page * $perPage, $total),
            ],
        ]);
    }

    public function create(): void
    {
        $tenantId = $this->tenantId();
        $this->render('quotes/form', [
            'quote'     => null,
            'items'     => [],
            'customers' => Customer::optionsForTenant($tenantId),
            'products'  => ProductService::optionsForTenant($tenantId),
            'csrf'      => Tool::generateCsrf(),
        ]);
    }

    public function edit(int $id): void
    {
        $tenantId = $this->tenantId();
        $quote = Quote::findInTenant($tenantId, $id);
        if (!$quote) { Session::flash('quote_msg', 'Quote not found.'); redirect('/Quotes'); }
        $this->render('quotes/form', [
            'quote'     => $quote,
            'items'     => Quote::itemsFor($id),
            'customers' => Customer::optionsForTenant($tenantId),
            'products'  => ProductService::optionsForTenant($tenantId),
            'csrf'      => Tool::generateCsrf(),
        ]);
    }

    public function save(): void
    {
        if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') redirect('/Quotes');
        if (!Tool::checkCsrf($_POST['_csrf'] ?? null)) {
            Session::flash('quote_msg', 'Session expired.'); redirect('/Quotes');
        }
        $tenantId = $this->tenantId();
        $userId   = $this->userId();
        $id       = (int) ($_POST['quote_id'] ?? 0);

        if (empty($_POST['customer_id'])) {
            Session::flash('quote_msg', 'Please select a customer.');
            redirect($id > 0 ? "/Quotes/edit/{$id}" : '/Quotes/create');
        }

        // Calculate totals from line items
        $subtotal = 0;
        $taxTotal = 0;
        $lineItems = [];
        if (!empty($_POST['item_description']) && is_array($_POST['item_description'])) {
            for ($i = 0, $n = count($_POST['item_description']); $i < $n; $i++) {
                $desc    = trim((string) ($_POST['item_description'][$i] ?? ''));
                $itemId  = !empty($_POST['item_product_id'][$i]) ? (int) $_POST['item_product_id'][$i] : null;
                $qty     = (float) ($_POST['item_qty'][$i] ?? 1);
                $price   = (float) ($_POST['item_price'][$i] ?? 0);
                $discPct = (float) ($_POST['item_discount'][$i] ?? 0);
                $line    = $qty * $price * (1 - $discPct / 100);
                $subtotal += $line;

                // Tax from product/service lookup, or 0 for ad-hoc
                $taxRate = 0;
                if ($itemId) {
                    $ps = ProductService::findInTenant($tenantId, (int) $itemId);
                    if ($ps && !empty($ps['taxable']) && $ps['unit_price'] > 0) {
                        $itemTaxRate = (float) ($ps['tax_rate'] ?? 0);
                        $taxTotal += $line * ($itemTaxRate / 100);
                    }
                }

                $lineItems[] = [
                    'item_id'          => $itemId,
                    'description'      => $desc !== '' ? $desc : 'Item ' . ($i + 1),
                    'quantity'         => $qty,
                    'unit_price'       => $price,
                    'discount_percent' => $discPct,
                    'line_total'       => round($line, 2),
                    'sort_order'       => $i,
                ];
            }
        }

        $discountPct  = (float) ($_POST['discount_percent'] ?? 0);
        $discountAmt  = $subtotal * ($discountPct / 100);
        $grandTotal   = round($subtotal - $discountAmt + $taxTotal, 2);

        $data = [
            'customer_id'      => (int) $_POST['customer_id'],
            'status'           => $_POST['status'] ?? 'draft',
            'subtotal'         => round($subtotal, 2),
            'discount_percent' => $discountPct,
            'discount_amount'  => round($discountAmt, 2),
            'tax_total'        => round($taxTotal, 2),
            'grand_total'      => $grandTotal,
            'valid_until'      => $_POST['valid_until'] ?? null,
            'notes'            => $_POST['notes'] ?? null,
            'terms'            => $_POST['terms'] ?? null,
            'created_by'       => $userId,
        ];

        if ($id > 0) {
            Quote::update($tenantId, $id, $data);
            // Remove existing items and re-add
            Quote::deleteAllItems($id);
            foreach ($lineItems as $li) {
                Quote::addItem($id, $li);
            }
            Session::flash('quote_msg', 'Quote updated.');
        } else {
            $id = Quote::create($tenantId, $data);
            foreach ($lineItems as $li) {
                Quote::addItem($id, $li);
            }
            Session::flash('quote_msg', 'Quote created.');
        }
        redirect("/Quotes/show/{$id}");
    }

    public function show(int $id): void
    {
        $tenantId = $this->tenantId();
        $quote = Quote::findInTenant($tenantId, $id);
        if (!$quote) { Session::flash('quote_msg', 'Not found.'); redirect('/Quotes'); }
        $this->render('quotes/show', [
            'quote' => $quote,
            'items' => Quote::itemsFor($id),
            'flash' => Session::flash('quote_msg'),
            'csrf'  => Tool::generateCsrf(),
        ]);
    }

    /**
     * Convert a quote into an invoice.
     * POST /Quotes/convertToInvoice/{id}
     */
    public function convertToInvoice(int $id): void
    {
        if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') redirect("/Quotes/show/{$id}");
        if (!Tool::checkCsrf($_POST['_csrf'] ?? null)) redirect("/Quotes/show/{$id}");
        $tenantId = $this->tenantId();
        $userId   = $this->userId();

        try {
            $invoiceId = Quote::convertToInvoice($tenantId, $id, $userId);
            Session::flash('invoice_msg', 'Quote converted to invoice successfully.');
            redirect("/Invoices/show/{$invoiceId}");
        } catch (\RuntimeException $e) {
            Session::flash('quote_msg', $e->getMessage());
            redirect("/Quotes/show/{$id}");
        }
    }

    public function delete(int $id): void
    {
        Quote::softDelete($this->tenantId(), $id);
        Session::flash('quote_msg', 'Quote deleted.');
        redirect('/Quotes');
    }

    public function pdf(int $id): void
    {
        $tenantId = $this->tenantId();
        $quote = Quote::findInTenant($tenantId, $id);
        if (!$quote) { http_response_code(404); echo 'Not found'; return; }
        $tenant = Tenant::findById($tenantId);
        $items  = Quote::itemsFor($id);
        ob_start();
        require ROOT . '/app/Views/pdf/quote.php';
        $html = ob_get_clean();
        Pdf::stream($html, 'Quote-' . ($quote['quote_number'] ?: $id));
    }
}