<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\Auth;
use App\Core\Csrf;
use App\Core\DB;
use App\Core\Request;
use App\Core\Response;
use App\Core\AppBootstrap;
use App\Repositories\SalesInvoiceRepository;
use App\Services\SalesInvoiceService;
use Throwable;
use App\Modules\Sales\Application\Services\SalesRouteContext;

final class SalesInvoiceController
{
    private \PDO $pdo;
    private SalesInvoiceRepository $salesInvoices;
    private SalesInvoiceService $service;
    private SalesRouteContext $routeContext;

    public function __construct()
    {
        $this->pdo = DB::pdo();
        $this->salesInvoices = new SalesInvoiceRepository($this->pdo);
        $this->service = new SalesInvoiceService($this->pdo, $this->salesInvoices);
        $this->routeContext = new SalesRouteContext();
    }

    public function index(): void
    {
        Auth::requireLogin();
        require_permission('sales.invoices.view');

        $dateFrom = trim((string) Request::get('from', Request::get('date_from', date('Y-m-01'))));
        $dateTo = trim((string) Request::get('to', Request::get('date_to', date('Y-m-d'))));
        $q = trim((string) Request::get('q', ''));
        $status = trim((string) Request::get('status', ''));
        $warehouseId = max(0, (int) Request::get('warehouse_id', 0));
        $partyId = max(0, (int) Request::get('party_id', Request::get('customer_id', 0)));
        $page = max(1, (int) Request::get('page', 1));
        $perPage = 25;

        $search = $this->salesInvoices->searchPage($dateFrom, $dateTo, $q, $status, $warehouseId, $partyId, $page, $perPage);
        $totalRows = (int) ($search['total_rows'] ?? 0);
        $totalPages = max(1, (int) ceil($totalRows / $perPage));
        if ($page > $totalPages) {
            $page = $totalPages;
            $search = $this->salesInvoices->searchPage($dateFrom, $dateTo, $q, $status, $warehouseId, $partyId, $page, $perPage);
        }
        $fromRow = $totalRows > 0 ? (($page - 1) * $perPage) + 1 : 0;
        $toRow = min($page * $perPage, $totalRows);
        $warehouses = $this->pdo->query("SELECT id, name FROM warehouses WHERE is_active=1 ORDER BY name")->fetchAll() ?: [];
        $selectedCustomer = $partyId > 0 ? ($this->salesInvoices->fetchCustomer($partyId) ?: null) : null;

        Response::view('pages/sales/index', [
            'invoices' => $search['rows'] ?? [],
            'page' => $page,
            'per_page' => $perPage,
            'total_pages' => $totalPages,
            'total_rows' => $totalRows,
            'from_row' => $fromRow,
            'to_row' => $toRow,
            'from' => $dateFrom,
            'to' => $dateTo,
            'q' => $q,
            'status' => $status,
            'warehouse_id' => $warehouseId,
            'party_id' => $partyId,
            'warehouses' => $warehouses,
            'selectedCustomer' => $selectedCustomer,
            'page_title' => 'فواتير المبيعات',
            'breadcrumbs' => [
                $this->routeContext->dashboardCrumb(),
                ['label' => 'المبيعات', 'url' => $this->routeContext->salesBoardPath()],
                ['label' => 'فواتير المبيعات'],
            ],
            'sales_invoices_url' => $this->routeContext->invoicesPath(),
            'sales_invoice_form_url' => $this->routeContext->invoiceFormPath(),
            'sales_invoice_view_base_url' => $this->routeContext->invoiceViewPath(),
        ]);
    }

    public function view(): void
    {
        Auth::requireLogin();
        require_permission('sales.invoices.view');

        $id = (int) Request::get('id', 0);
        if ($id <= 0) {
            Response::redirect($this->routeContext->invoicesPath());
            return;
        }

        $inv = $this->salesInvoices->findViewById($id);
        if (!$inv) {
            Response::redirect($this->routeContext->invoicesPath());
            return;
        }

        Response::view('pages/sales/invoice_view', [
            'inv' => $inv,
            'lines' => $this->salesInvoices->fetchLines($id),
            'salesReturnSummary' => $this->salesInvoices->fetchSalesReturnSummary($id),
            'page_title' => 'عرض فاتورة مبيعات',
            'breadcrumbs' => [
                $this->routeContext->dashboardCrumb(),
                ['label'=>'فواتير المبيعات','url'=>$this->routeContext->invoicesPath()],
                ['label'=>'عرض'],
            ],
            'sales_invoices_url' => $this->routeContext->invoicesPath(),
            'sales_invoice_form_url' => $this->routeContext->invoiceFormPath(),
            'sales_return_form_url' => $this->routeContext->returnFormPath(),
            'sales_returns_url' => $this->routeContext->returnsPath(),
        ]);
    }

    public function form(): void
    {
        Auth::requireLogin();
        AppBootstrap::bootSalesInvoices($this->pdo);
        try {
            $this->pdo->query("SELECT customer_id, status, grand_total, vat_rate FROM sales_invoices LIMIT 1");
        } catch (Throwable) {
            Response::view('pages/dashboard', ['error' => 'مطلوب تشغيل ملف التحديث: sql/migrate_v1_40_sales_invoices_v2.sql']);
            return;
        }

        $id = (int) Request::get('id', 0);
        $isEdit = $id > 0;
        if ($isEdit) {
            require_permission('sales.invoices.edit');
        } else {
            require_permission('sales.invoices.create');
        }

        $warehouses = $this->pdo->query("SELECT id, name FROM warehouses WHERE is_active=1 ORDER BY name")->fetchAll();
        $units = $this->pdo->query("SELECT id, name FROM units ORDER BY name")->fetchAll();
        $cashboxes = $this->pdo->query("SELECT id, name FROM cashboxes WHERE is_active=1 ORDER BY name")->fetchAll();

        $invoice = $this->salesInvoices->findById($id);
        $lines = $isEdit ? $this->salesInvoices->fetchLines($id) : [];
        if ($isEdit && !$invoice) {
            http_response_code(404);
            exit('Not found');
        }
        if ($isEdit && strtoupper((string) $invoice['status']) !== 'DRAFT') {
            Response::flash('danger', 'لا يمكن تعديل فاتورة مرحّلة.');
            Response::redirect($this->routeContext->invoiceViewPath($id));
            return;
        }

        $invoice = $invoice ?: $this->service->defaultInvoice($warehouses, $cashboxes);
        $oldForm = $_SESSION['sales_invoice_form_old'] ?? null;
        if (is_array($oldForm)) {
            $invoice = array_merge($invoice, $oldForm['invoice'] ?? []);
            $lines = $oldForm['lines'] ?? $lines;
            unset($_SESSION['sales_invoice_form_old']);
        }

        $customer = null;
        if (!empty($invoice['party_id']) || !empty($invoice['customer_id'])) {
            $partyId = (int)($invoice['party_id'] ?? 0) ?: (int)($invoice['customer_id'] ?? 0);
            $customer = $this->salesInvoices->fetchCustomer($partyId) ?: null;
        }

        if (Request::isPost()) {
            Csrf::verify();
            $action = (string) Request::post('action', 'save');
            if ($action === 'post') {
                require_permission('sales.invoices.post');
            }
            $payload = $this->buildFormPayload();
            try {
                $savedId = $this->service->save($id, $isEdit, Request::all(), current_user_id() ? (int) current_user_id() : null);
                $this->clearOld();
                Response::flash('success', ($action === 'post') ? 'تم الترحيل' : 'تم الحفظ كمسودة');
                Response::redirect($this->routeContext->invoiceViewPath($savedId));
                return;
            } catch (Throwable $e) {
                $this->storeOld($payload);
                $msg = (string) $e->getMessage();
                if (stripos($msg, 'SQLSTATE[HY093]') !== false) {
                    $msg = 'حدث خطأ داخلي أثناء حفظ الفاتورة. تم إصلاح سبب شائع متعلق بعملية الحفظ، ولو استمرت المشكلة أعد تحميل الصفحة وجرب مرة أخرى.';
                } elseif (stripos($msg, 'Duplicate entry') !== false) {
                    $msg = 'يوجد تكرار في البيانات المدخلة. راجع رقم المستند أو الأصناف داخل الفاتورة.';
                } else {
                    $msg = 'تعذر حفظ الفاتورة: ' . $msg;
                }
                Response::flash('danger', $msg);
                Response::redirect($this->formRedirectUrl($isEdit, $id));
                return;
            }
        }

        Response::view('pages/sales/invoice_form', [
            'invoice' => $invoice,
            'lines' => $lines,
            'warehouses' => $warehouses,
            'units' => $units,
            'cashboxes' => $cashboxes,
            'customer' => $customer,
            'isEdit' => $isEdit,
            'page_title' => $isEdit ? 'تعديل فاتورة مبيعات' : 'إنشاء فاتورة مبيعات',
            'breadcrumbs' => [
                $this->routeContext->dashboardCrumb(),
                ['label' => 'فواتير المبيعات', 'url' => $this->routeContext->invoicesPath()],
                ['label' => $isEdit ? 'تعديل' : 'إنشاء'],
            ],
            'sales_invoices_url' => $this->routeContext->invoicesPath(),
            'sales_invoice_view_url' => $this->routeContext->invoiceViewPath($id),
        ]);
    }



    public function deleteDraft(): void
    {
        Auth::requireLogin();
        require_permission('sales.invoices.edit');
        Csrf::verify();

        $id = (int) Request::post('id', Request::get('id', 0));
        if ($id <= 0) {
            Response::flash('danger', 'فاتورة غير صحيحة.');
            Response::redirect($this->routeContext->invoicesPath());
            return;
        }

        try {
            $this->service->deleteDraft($id, current_user_id() ? (int) current_user_id() : null);
            Response::flash('success', 'تم حذف الفاتورة المسودة.');
            Response::redirect($this->routeContext->invoicesPath());
            return;
        } catch (Throwable $e) {
            Response::flash('danger', 'تعذر حذف المسودة: ' . $e->getMessage());
            Response::redirect($this->routeContext->invoiceViewPath($id));
            return;
        }
    }

    private function buildFormPayload(): array
    {
        $invoice = [
            'invoice_date' => (string) Request::post('invoice_date', date('Y-m-d')),
            'warehouse_id' => (int) Request::post('warehouse_id', 0),
            'party_id' => (int) Request::post('party_id', Request::post('customer_id', 0)),
            'customer_id' => (int) Request::post('party_id', Request::post('customer_id', 0)),
            'discount_type' => (string) Request::post('discount_type', 'PERCENT'),
            'discount_value' => (float) Request::post('discount_value', 0),
            'discount_note' => (string) Request::post('discount_note', ''),
            'vat_enabled' => Request::post('vat_enabled', null) !== null ? 1 : 0,
            'vat_rate' => (float) Request::post('vat_rate', 14),
            'notes' => (string) Request::post('notes', ''),
            'payment_mode' => (string) Request::post('payment_mode', 'credit'),
            'paid_amount' => (float) Request::post('paid_amount', 0),
            'due_amount' => 0,
            'cashbox_id' => (int) Request::post('cashbox_id', 0),
            'collection_note' => (string) Request::post('collection_note', ''),
            'customer_label' => (string) Request::post('customer_label', ''),
        ];
        $itemIds = Request::post('item_id', []);
        $qtys = Request::post('qty', []);
        $prices = Request::post('price', []);
        $names = Request::post('item_name', []);
        $lines = [];
        foreach ($itemIds as $i => $itemId) {
            $qty = (float)($qtys[$i] ?? 0);
            $price = max(0, (float)($prices[$i] ?? 0));
            $lines[] = [
                'item_id' => (int)$itemId,
                'item_name' => (string)($names[$i] ?? ''),
                'qty' => $qty > 0 ? $qty : 1,
                'price' => $price,
                'line_total' => round(max(0, $qty) * $price, 2),
            ];
        }
        return ['invoice' => $invoice, 'lines' => $lines];
    }

    private function formRedirectUrl(bool $isEdit, int $id): string
    {
        return $this->routeContext->invoiceFormPath($isEdit ? $id : 0);
    }

    private function storeOld(array $payload): void
    {
        $_SESSION['sales_invoice_form_old'] = $payload;
    }

    private function clearOld(): void
    {
        unset($_SESSION['sales_invoice_form_old']);
    }
}
