<?php

declare(strict_types=1);

namespace App\Modules\Reporting\Presentation\Controllers;

use App\Core\Auth;
use App\Core\Request;
use App\Core\Response;
use App\Modules\Reporting\Application\Services\InventoryReportService;
use App\Modules\Reporting\Application\Services\ReportFileExportService;

final class InventoryReportController
{
    public function __construct(private ?InventoryReportService $service = null)
    {
        $this->service ??= new InventoryReportService(db());
    }

    public function stock(): void
    {
        Auth::requireLogin();
        require_permission('items.view');

        $onlyNonzero = (int) Request::get('only_nonzero', 0);
        $data = $this->service->stockReport((int) Request::get('warehouse_id', 1), 2000, $onlyNonzero);
        $page = max(1, (int) Request::get('page', 1));
        $pagination = paginate_rows($data['rows'] ?? [], $page, 25);
        $data['rows'] = $pagination['items'];
        Response::view('pages/stock_report', $data + [
            'page' => $pagination['page'],
            'per_page' => $pagination['per_page'],
            'total_pages' => $pagination['total_pages'],
            'total_rows' => $pagination['total_rows'],
            'from_row' => $pagination['from'],
            'to_row' => $pagination['to'],
            'only_nonzero' => $onlyNonzero,
            'hide_page_header' => true,
            'page_title' => 'تقرير المخزون',
            'breadcrumbs' => [
                ['label' => 'لوحة التحكم', 'url' => '/admin/dashboard'],
                ['label' => 'تقرير المخزون'],
            ],
        ]);
    }

    public function printStock(): void
    {
        Auth::requireLogin();
        require_permission('items.view');

        $format = strtolower(trim((string) Request::get('format', '')));
        if ($format === '') {
            $this->chooseFormat('طباعة تقرير المخزون', false);
            return;
        }
        if ($format !== 'a4') { $format = 'a4'; }

        $onlyNonzero = (int) Request::get('only_nonzero', 1);
        $data = $this->service->stockReport((int) Request::get('warehouse_id', 1), 5000, $onlyNonzero);
        print_view('report', 'generic_report', $this->withReportPrintDefaults($this->stockGenericPrintPayload($data, $onlyNonzero)));
    }



    public function supplierStock(): void
    {
        Auth::requireLogin();
        require_permission('purchases.reports.view');

        $data = $this->service->supplierStock(
            (int) Request::get('warehouse_id', 0),
            (int) Request::get('party_id', Request::get('supplier_id', 0)),
            (int) Request::get('only_nonzero', 1),
        );
        $page = max(1, (int) Request::get('page', 1));
        $pagination = paginate_rows($data['rows'] ?? [], $page, 25);
        $data['rows'] = $pagination['items'];

        Response::view('pages/suppliers/stock_report', $data + [
            'page' => $pagination['page'],
            'per_page' => $pagination['per_page'],
            'total_pages' => $pagination['total_pages'],
            'total_rows' => $pagination['total_rows'],
            'from_row' => $pagination['from'],
            'to_row' => $pagination['to'],
            'supplier_id' => $data['party_id'],
            'hide_page_header' => true,
            'page_title' => 'تقرير مخزون الطرف',
            'breadcrumbs' => [
                ['label' => 'لوحة التحكم', 'url' => '/admin/dashboard'],
                ['label' => 'تقرير مخزون الطرف'],
            ],
        ]);
    }

    public function printSupplierStock(): void
    {
        Auth::requireLogin();
        require_permission('purchases.reports.view');

        $format = strtolower(trim((string) Request::get('format', '')));
        if ($format === '') {
            $this->chooseFormat('طباعة تقرير مخزون مورد', false);
            return;
        }
        if ($format !== 'a4') { $format = 'a4'; }

        $onlyNonzero = (int) Request::get('only_nonzero', 0);
        $data = $this->service->supplierStock(
            (int) Request::get('warehouse_id', 0),
            (int) Request::get('party_id', Request::get('supplier_id', 0)),
            $onlyNonzero,
            10000,
        );

        if (($data['party_id'] ?? 0) <= 0) {
            http_response_code(400);
            exit('Invalid supplier');
        }
        if (($data['supplier']['id'] ?? 0) <= 0) {
            http_response_code(404);
            exit('Supplier not found');
        }

        print_view('report', 'generic_report', $this->withReportPrintDefaults($this->supplierStockGenericPrintPayload($data, $onlyNonzero)));
    }


    public function itemMovement(): void
    {
        Auth::requireLogin();
        require_permission('items.view');

        $data = $this->service->itemMovement(
            (int) Request::get('warehouse_id', 0),
            (int) Request::get('item_id', 0),
            trim((string) Request::get('from', '')),
            trim((string) Request::get('to', '')),
        );

        Response::view('pages/item_movement_report', $data + [
            'page_title' => 'تقرير حركة صنف',
            'breadcrumbs' => [
                ['label' => 'لوحة التحكم', 'url' => '/admin/dashboard'],
                ['label' => 'تقرير حركة صنف'],
            ],
        ]);
    }

    public function printItemMovement(): void
    {
        Auth::requireLogin();
        require_permission('items.view');

        $format = strtolower(trim((string) Request::get('format', '')));
        if ($format === '') {
            $this->chooseFormat('طباعة تقرير حركة صنف', false);
            return;
        }
        if ($format !== 'a4') { $format = 'a4'; }

        $data = $this->service->itemMovement(
            (int) Request::get('warehouse_id', 0),
            (int) Request::get('item_id', 0),
            trim((string) Request::get('from', '')),
            trim((string) Request::get('to', '')),
        );

        if (($data['item_id'] ?? 0) <= 0 || ($data['meta']['item_name'] ?? '') === '') {
            http_response_code(400);
            exit('Invalid item_id');
        }

        print_view('report', 'generic_report', $this->withReportPrintDefaults($this->itemMovementGenericPrintPayload($data)));
    }


    public function exportStockExcel(): void
    {
        Auth::requireLogin();
        require_permission('items.view');
        $onlyNonzero = (int) Request::get('only_nonzero', 0);
        $data = $this->service->stockReport((int) Request::get('warehouse_id', 1), 50000, $onlyNonzero);
        $rows = [];
        $i = 0;
        foreach (($data['rows'] ?? []) as $r) {
            $i++;
            $qty = (float)($r['qty'] ?? 0);
            $cost = (float)($r['cost'] ?? 0);
            $rows[] = [$i, (string)($r['name'] ?? ''), (string)($r['barcode'] ?? ''), format_money($cost), format_money($r['price'] ?? 0), format_qty($qty), format_money($qty * $cost)];
        }
        (new ReportFileExportService())->sendExcel('stock-report-' . date('Ymd-His'), 'تقرير المخزون', [
            'المخزن' => (string)($data['warehouse_name'] ?? ''),
            'وضع الطباعة' => $onlyNonzero === 1 ? 'الأصناف ذات الرصيد فقط' : 'كل الأصناف',
            'إجمالي قيمة التكلفة' => format_money($data['total_cost_value'] ?? 0),
        ], ['#','الصنف','باركود','التكلفة','السعر','الرصيد','قيمة التكلفة'], $rows);
    }

    public function exportStockPdf(): void
    {
        Auth::requireLogin();
        require_permission('items.view');
        $_GET['format'] = 'a4';
        ob_start();
        $this->printStock();
        $html = (string)ob_get_clean();
        (new ReportFileExportService())->sendPdfFromHtml($html, 'stock-report-' . date('Ymd-His'));
    }

    public function exportSupplierStockExcel(): void
    {
        Auth::requireLogin();
        require_permission('purchases.reports.view');
        $onlyNonzero = (int) Request::get('only_nonzero', 0);
        $data = $this->service->supplierStock((int) Request::get('warehouse_id', 0), (int) Request::get('party_id', Request::get('supplier_id', 0)), $onlyNonzero, 50000);
        $rows = [];
        $i = 0;
        foreach (($data['rows'] ?? []) as $r) {
            $i++;
            $qty = (float)($r['qty'] ?? 0);
            $cost = (float)($r['cost'] ?? 0);
            $rows[] = [$i, (string)($r['name'] ?? ''), (string)($r['barcode'] ?? ''), format_money($cost), format_money($r['price'] ?? 0), format_qty($qty), format_money($qty * $cost)];
        }
        (new ReportFileExportService())->sendExcel('supplier-stock-' . date('Ymd-His'), 'تقرير مخزون الطرف', [
            'الطرف' => (string)($data['supplier_name'] ?? ''),
            'المخزن' => (string)($data['warehouse_name'] ?? ''),
            'إجمالي قيمة التكلفة' => format_money($data['total_cost_value'] ?? 0),
        ], ['#','الصنف','باركود','التكلفة','السعر','الرصيد','قيمة التكلفة'], $rows);
    }

    public function exportSupplierStockPdf(): void
    {
        Auth::requireLogin();
        require_permission('purchases.reports.view');
        $_GET['format'] = 'a4';
        ob_start();
        $this->printSupplierStock();
        $html = (string)ob_get_clean();
        (new ReportFileExportService())->sendPdfFromHtml($html, 'supplier-stock-' . date('Ymd-His'));
    }

    public function exportItemMovementExcel(): void
    {
        Auth::requireLogin();
        require_permission('items.view');
        $data = $this->service->itemMovement((int) Request::get('warehouse_id', 0), (int) Request::get('item_id', 0), trim((string) Request::get('from', '')), trim((string) Request::get('to', '')));
        $running = (float)($data['opening'] ?? 0);
        $rows = [];
        $rows[] = [0, (string)($data['from'] ?? ''), 'رصيد أول المدة', '', '', '', '', format_qty($running)];
        $i = 0;
        foreach (($data['moves'] ?? []) as $m) {
            $i++;
            $in = (float)($m['qty_in'] ?? 0);
            $out = (float)($m['qty_out'] ?? 0);
            $running += $in - $out;
            $rows[] = [$i, (string)($m['created_at'] ?? ''), (string)($m['ref_label'] ?? $m['ref_type'] ?? ''), (string)($m['ref_no'] ?? $m['ref_id'] ?? ''), format_qty($in), format_qty($out), (string)($m['username'] ?? ''), format_qty($running)];
        }
        $meta = is_array($data['meta'] ?? null) ? $data['meta'] : [];
        (new ReportFileExportService())->sendExcel('item-movement-' . date('Ymd-His'), 'تقرير حركة صنف', [
            'الصنف' => (string)($meta['item_name'] ?? ''),
            'المخزن' => (string)($meta['warehouse_name'] ?? ''),
            'الفترة' => (string)($data['from'] ?? '') . ' - ' . (string)($data['to'] ?? ''),
        ], ['#','التاريخ','النوع','المرجع','وارد','منصرف','المستخدم','الرصيد'], $rows);
    }

    public function exportItemMovementPdf(): void
    {
        Auth::requireLogin();
        require_permission('items.view');
        $_GET['format'] = 'a4';
        ob_start();
        $this->printItemMovement();
        $html = (string)ob_get_clean();
        (new ReportFileExportService())->sendPdfFromHtml($html, 'item-movement-' . date('Ymd-His'));
    }


    /**
     * Build the unified reports-print payload for stock balance report.
     * The old inventory print route was redirected to generic_report, but the
     * payload helpers were missing, causing a fatal error on /reports/inventory/stock/print.
     *
     * @param array<string,mixed> $data
     * @return array<string,mixed>
     */
    private function stockGenericPrintPayload(array $data, int $onlyNonzero): array
    {
        $rows = [];
        $i = 0;
        foreach (($data['rows'] ?? []) as $row) {
            $i++;
            $qty = (float)($row['qty'] ?? 0);
            $cost = (float)($row['cost'] ?? 0);
            $rows[] = [
                'no' => (string)$i,
                'item' => (string)($row['name'] ?? ''),
                'barcode' => (string)($row['barcode'] ?? '-'),
                'cost' => format_money($cost),
                'price' => format_money($row['price'] ?? 0),
                'qty' => format_qty($qty),
                'cost_value' => format_money($qty * $cost),
            ];
        }

        $totalQty = 0.0;
        foreach (($data['rows'] ?? []) as $row) {
            $totalQty += (float)($row['qty'] ?? 0);
        }

        return [
            'title' => 'تقرير المخزون',
            'report' => [
                'title' => 'تقرير المخزون',
                'description' => 'أرصدة الأصناف وقيمة التكلفة حسب المخزن والفلاتر.',
            ],
            'columns' => [
                'no' => '#',
                'item' => 'الصنف',
                'barcode' => 'باركود',
                'cost' => 'التكلفة',
                'price' => 'السعر',
                'qty' => 'الرصيد',
                'cost_value' => 'قيمة التكلفة',
            ],
            'rows' => $rows,
            'summary' => [
                'عدد الأصناف' => (string)count($rows),
                'إجمالي الكمية' => format_qty($totalQty),
                'إجمالي قيمة التكلفة' => format_money($data['total_cost_value'] ?? 0),
            ],
            'filters' => [
                'non_zero' => $onlyNonzero === 1 ? 1 : 0,
            ],
            'lookups' => [
                'selected_warehouse' => ['text' => (string)($data['warehouse_name'] ?? '')],
            ],
            'reportDate' => date('Y-m-d'),
            'userName' => Auth::name(),
        ];
    }

    /** @param array<string,mixed> $data @return array<string,mixed> */
    private function supplierStockGenericPrintPayload(array $data, int $onlyNonzero): array
    {
        $rows = [];
        $i = 0;
        foreach (($data['rows'] ?? []) as $row) {
            $i++;
            $qty = (float)($row['qty'] ?? 0);
            $cost = (float)($row['cost'] ?? 0);
            $rows[] = [
                'no' => (string)$i,
                'item' => (string)($row['name'] ?? ''),
                'barcode' => (string)($row['barcode'] ?? '-'),
                'cost' => format_money($cost),
                'price' => format_money($row['price'] ?? 0),
                'qty' => format_qty($qty),
                'cost_value' => format_money($qty * $cost),
            ];
        }

        $totalQty = 0.0;
        foreach (($data['rows'] ?? []) as $row) {
            $totalQty += (float)($row['qty'] ?? 0);
        }

        return [
            'title' => 'تقرير مخزون المورد',
            'report' => [
                'title' => 'تقرير مخزون المورد',
                'description' => 'أرصدة الأصناف المرتبطة بالمورد حسب المخزن والفلاتر.',
            ],
            'columns' => [
                'no' => '#',
                'item' => 'الصنف',
                'barcode' => 'باركود',
                'cost' => 'التكلفة',
                'price' => 'السعر',
                'qty' => 'الرصيد',
                'cost_value' => 'قيمة التكلفة',
            ],
            'rows' => $rows,
            'summary' => [
                'عدد الأصناف' => (string)count($rows),
                'إجمالي الكمية' => format_qty($totalQty),
                'إجمالي قيمة التكلفة' => format_money($data['total_cost_value'] ?? 0),
            ],
            'filters' => [
                'non_zero' => $onlyNonzero === 1 ? 1 : 0,
            ],
            'filter_config' => ['party_label' => 'المورد'],
            'lookups' => [
                'selected_party' => ['text' => (string)($data['supplier_name'] ?? '')],
                'selected_warehouse' => ['text' => (string)($data['warehouse_name'] ?? '')],
            ],
            'reportDate' => date('Y-m-d'),
            'userName' => Auth::name(),
        ];
    }

    /** @param array<string,mixed> $data @return array<string,mixed> */
    private function itemMovementGenericPrintPayload(array $data): array
    {
        $meta = is_array($data['meta'] ?? null) ? $data['meta'] : [];
        $rows = [];
        $running = (float)($data['opening'] ?? 0);
        $rows[] = [
            'date' => (string)($data['from'] ?? ''),
            'type' => 'رصيد افتتاحي',
            'ref' => '-',
            'in' => '-',
            'out' => '-',
            'user' => '-',
            'balance' => format_qty($running),
        ];
        foreach (($data['moves'] ?? []) as $move) {
            $in = (float)($move['qty_in'] ?? 0);
            $out = (float)($move['qty_out'] ?? 0);
            $running += $in - $out;
            $rows[] = [
                'date' => (string)($move['created_at'] ?? ''),
                'type' => (string)($move['ref_label'] ?? $move['ref_type'] ?? ''),
                'ref' => (string)($move['ref_no'] ?? $move['ref_id'] ?? ''),
                'in' => $in > 0 ? format_qty($in) : '-',
                'out' => $out > 0 ? format_qty($out) : '-',
                'user' => (string)($move['username'] ?? ''),
                'balance' => format_qty($running),
            ];
        }

        return [
            'title' => 'تقرير حركة صنف',
            'report' => [
                'title' => 'تقرير حركة صنف',
                'description' => 'حركة الوارد والمنصرف والرصيد لصنف محدد خلال فترة.',
            ],
            'columns' => [
                'date' => 'التاريخ',
                'type' => 'نوع الحركة',
                'ref' => 'رقم المستند',
                'in' => 'وارد',
                'out' => 'منصرف',
                'user' => 'المستخدم',
                'balance' => 'الرصيد',
            ],
            'rows' => $rows,
            'summary' => [
                'رصيد أول المدة' => format_qty($data['opening'] ?? 0),
                'إجمالي الوارد' => format_qty($data['tot_in'] ?? 0),
                'إجمالي المنصرف' => format_qty($data['tot_out'] ?? 0),
                'الرصيد النهائي' => format_qty($running),
            ],
            'filters' => [
                'from' => (string)($data['from'] ?? ''),
                'to' => (string)($data['to'] ?? ''),
            ],
            'lookups' => [
                'selected_item' => ['text' => (string)($meta['item_name'] ?? '')],
                'selected_warehouse' => ['text' => (string)($meta['warehouse_name'] ?? '')],
            ],
            'reportDate' => date('Y-m-d'),
            'userName' => Auth::name(),
        ];
    }

    /**
     * Add the same unified reports print context used by GenericReportController.
     * Without these keys the old inventory print routes render generic_report with
     * an empty company block, so the logo/company details disappear.
     *
     * @param array<string,mixed> $payload
     * @return array<string,mixed>
     */
    private function withReportPrintDefaults(array $payload): array
    {
        return $payload + [
            'meta' => ['date' => date('Y-m-d')],
            'company' => company_profile(db()),
            'footer' => ['note' => 'هذا التقرير صادر من مركز التقارير ويطابق نسخة الطباعة ونسخة PDF.'],
            'print_format' => 'a4',
            'print_options' => ['report_mode' => true, 'show_signatures' => false],
            'report_mode' => true,
            'userName' => current_user_name(),
            'reportDate' => date('Y-m-d'),
        ];
    }

    private function chooseFormat(string $title, bool $allowReceipt = true): void
    {
        $basePath = Request::path();
        $qs = $_GET;
        $qs['format'] = 'a4';
        $a4Url = $basePath . '?' . http_build_query($qs);
        $receiptUrl = '';
        if ($allowReceipt) {
            $qs['format'] = 'receipt';
            $receiptUrl = $basePath . '?' . http_build_query($qs);
        }
        print_format_chooser($a4Url, $receiptUrl, $title);
    }
}
