<?php

declare(strict_types=1);

namespace App\Modules\Reporting\Application\Services;

use App\Shared\Schema\PartySchemaSupport;
use App\Shared\Schema\QuotationSchemaSupport;
use PDO;
use RuntimeException;

final class DocumentPrintService
{
    public function check(PDO $pdo, int $id): array
    {
        $st = $pdo->prepare("SELECT c.*, p.name drawer_name, COALESCE(p.code, CONCAT('P',LPAD(p.id,5,'0'))) drawer_code, sp.name supplier_name
                             FROM checks c
                             JOIN parties p ON p.id=c.drawer_party_id
                             LEFT JOIN parties sp ON sp.id=c.last_endorsed_party_id
                             WHERE c.id=? LIMIT 1");
        $st->execute([$id]);
        $check = $st->fetch();
        if (!$check) {
            throw new RuntimeException('Not found', 404);
        }

        $st = $pdo->prepare("SELECT m.*, p.name party_name FROM check_movements m LEFT JOIN parties p ON p.id=m.party_id WHERE m.check_id=? ORDER BY m.id ASC");
        $st->execute([$id]);
        $movements = $st->fetchAll() ?: [];

        return [
            'view' => 'check',
            'title' => 'شيك',
            'meta' => [
                'no' => (string)($check['check_no'] ?? ''),
                'date' => (string)substr((string)($check['receive_date'] ?? ''), 0, 10),
                'status' => check_status_label((string)($check['current_status'] ?? '')),
            ],
            'company' => company_profile($pdo),
            'footer' => ['page_hint' => ''],
            'payload' => compact('check', 'movements'),
        ];
    }

    public function customer(PDO $pdo, int $id): array
    {
        PartySchemaSupport::ensurePartiesSchema($pdo);
        $st = $pdo->prepare("SELECT * FROM parties WHERE id=? LIMIT 1");
        $st->execute([$id]);
        $row = $st->fetch();
        if (!$row) {
            throw new RuntimeException('Not found', 404);
        }

        $labels = [
            'code' => 'كود العميل',
            'name' => 'الاسم',
            'phone' => 'الهاتف',
            'email' => 'البريد',
            'address' => 'العنوان',
            'credit_limit' => 'الحد الائتماني',
            'notes' => 'ملاحظات',
        ];

        return [
            'view' => 'entity_card',
            'title' => 'بيانات عميل',
            'meta' => ['no' => (string)($row['code'] ?? $row['customer_code'] ?? '')],
            'company' => company_profile($pdo),
            'footer' => [],
            'payload' => compact('row', 'labels'),
        ];
    }

    public function supplier(PDO $pdo, int $id): array
    {
        PartySchemaSupport::ensurePartiesSchema($pdo);
        $st = $pdo->prepare("SELECT * FROM parties WHERE id=? LIMIT 1");
        $st->execute([$id]);
        $row = $st->fetch();
        if (!$row) {
            throw new RuntimeException('Not found', 404);
        }

        $labels = [
            'code' => 'كود المورد',
            'name' => 'الاسم',
            'phone' => 'الهاتف',
            'email' => 'البريد',
            'address' => 'العنوان',
            'notes' => 'ملاحظات',
        ];

        return [
            'view' => 'entity_card',
            'title' => 'بيانات مورد',
            'meta' => ['no' => (string)($row['code'] ?? '')],
            'company' => company_profile($pdo),
            'footer' => [],
            'payload' => compact('row', 'labels'),
        ];
    }

    public function salesInvoice(PDO $pdo, int $id): array
    {
        $st = $pdo->prepare("SELECT si.*, c.name customer_name, w.name warehouse_name
                             FROM sales_invoices si
                             LEFT JOIN parties c ON c.id = COALESCE(si.party_id, si.customer_id)
                             LEFT JOIN warehouses w ON w.id=si.warehouse_id
                             WHERE si.id=? LIMIT 1");
        $st->execute([$id]);
        $inv = $st->fetch();
        if (!$inv) {
            throw new RuntimeException('Not found', 404);
        }

        $st = $pdo->prepare("SELECT * FROM sales_items WHERE invoice_id=? ORDER BY id");
        $st->execute([$id]);
        $lines = $st->fetchAll() ?: [];

        return [
            'view' => 'sales_invoice',
            'title' => 'فاتورة مبيعات',
            'meta' => [
                'no' => (string)($inv['invoice_no'] ?? ''),
                'date' => (string)substr((string)($inv['invoice_date'] ?? ''), 0, 10),
                'status' => (string)($inv['status'] ?? ''),
                'note' => 'فاتورة مبيعات احترافية مهيأة للطباعة الرسمية أو التسليم للعميل.',
                'title_en' => 'Sales Invoice',
            ],
            'company' => company_profile($pdo),
            'footer' => ['page_hint' => '', 'note' => 'يرجى مراجعة الكميات والإجماليات قبل اعتماد الفاتورة.'],
            'print_template' => 'purchase_invoice_v2',
            'payload' => compact('inv', 'lines'),
        ];
    }

    public function purchaseInvoice(PDO $pdo, int $id): array
    {
        if (!table_exists($pdo, 'purchase_invoices')) {
            throw new RuntimeException('مطلوب تشغيل ملف التحديث: sql/migrate_v1_23_purchases.sql', 500);
        }

        $hasWht = true;
        try {
            $pdo->query("SELECT wht_enabled, wht_rate, wht_amount FROM purchase_invoices LIMIT 1");
        } catch (\Throwable $e) {
            $hasWht = false;
        }
        if (!$hasWht) {
            throw new RuntimeException('مطلوب تشغيل ملف التحديث: sql/migrate_v1_24_purchase_withholding.sql', 500);
        }

        $st = $pdo->prepare("SELECT pi.*, s.name supplier_name, COALESCE(s.code, CONCAT('P',LPAD(s.id,5,'0'))) supplier_code,
                                    w.name warehouse_name
                             FROM purchase_invoices pi
                             JOIN parties s ON s.id=COALESCE(pi.party_id, pi.supplier_id)
                             JOIN warehouses w ON w.id=pi.warehouse_id
                             WHERE pi.id=? LIMIT 1");
        $st->execute([$id]);
        $inv = $st->fetch();
        if (!$inv) {
            throw new RuntimeException('Not found', 404);
        }

        $st = $pdo->prepare("SELECT l.*, i.name item_name, u.name unit_name, u.symbol unit_symbol
                             FROM purchase_invoice_lines l
                             JOIN items i ON i.id = l.item_id
                             LEFT JOIN units u ON u.id = l.unit_id
                             WHERE l.invoice_id=?
                             ORDER BY l.line_no");
        $st->execute([$id]);
        $lines = $st->fetchAll() ?: [];

        return [
            'view' => 'purchase_invoice',
            'title' => 'فاتورة شراء',
            'meta' => [
                'no' => (string)($inv['inv_no'] ?? ''),
                'date' => (string)substr((string)($inv['inv_date'] ?? ''), 0, 10),
                'status' => (string)($inv['status'] ?? ''),
                'title_en' => 'Purchase Invoice',
            ],
            'company' => company_profile($pdo),
            'footer' => ['page_hint' => '', 'note' => 'هذه الفاتورة توضح الأصناف والتكلفة النهائية بعد الخصم والضرائب إن وجدت.'],
            'print_template' => 'purchase_invoice_v2',
            'payload' => compact('inv', 'lines'),
        ];
    }

    public function purchaseReturn(PDO $pdo, int $id): array
    {
        $st = $pdo->prepare("SELECT pr.*, s.name supplier_name, COALESCE(s.code, CONCAT('P',LPAD(s.id,5,'0'))) supplier_code,
                                    w.name warehouse_name, pi.inv_no source_inv_no
                             FROM purchase_returns pr
                             JOIN parties s ON s.id=COALESCE(pr.party_id, pr.supplier_id)
                             JOIN warehouses w ON w.id=pr.warehouse_id
                             JOIN purchase_invoices pi ON pi.id=pr.source_invoice_id
                             WHERE pr.id=? LIMIT 1");
        $st->execute([$id]);
        $ret = $st->fetch();
        if (!$ret) {
            throw new RuntimeException('Not found', 404);
        }

        $st = $pdo->prepare("SELECT l.*, i.name item_name, u.name unit_name
                             FROM purchase_return_lines l
                             JOIN items i ON i.id = l.item_id
                             LEFT JOIN units u ON u.id = l.unit_id
                             WHERE l.return_id=?
                             ORDER BY l.line_no");
        $st->execute([$id]);
        $lines = $st->fetchAll() ?: [];

        return [
            'view' => 'purchase_return',
            'title' => 'مرتجع شراء',
            'meta' => [
                'no' => (string)($ret['ret_no'] ?? ''),
                'date' => (string)substr((string)($ret['ret_date'] ?? ''), 0, 10),
                'status' => (string)($ret['status'] ?? ''),
            ],
            'company' => company_profile($pdo),
            'footer' => [],
            'payload' => compact('ret', 'lines'),
        ];
    }

    public function salesReturn(PDO $pdo, int $id): array
    {
        $st = $pdo->prepare("SELECT sr.*, p.name customer_name, COALESCE(p.code, CONCAT('P',LPAD(p.id,5,'0'))) customer_code,
                                    w.name warehouse_name, si.invoice_no source_inv_no, cb.name cashbox_name
                             FROM sales_returns sr
                             JOIN parties p ON p.id = sr.party_id
                             JOIN warehouses w ON w.id = sr.warehouse_id
                             JOIN sales_invoices si ON si.id = sr.sales_invoice_id
                             LEFT JOIN cashboxes cb ON cb.id = sr.cashbox_id
                             WHERE sr.id=? LIMIT 1");
        $st->execute([$id]);
        $ret = $st->fetch();
        if (!$ret) {
            throw new RuntimeException('Not found', 404);
        }

        $st = $pdo->prepare("SELECT sri.*, s.item_name
                             FROM sales_return_items sri
                             LEFT JOIN sales_items s ON s.id = sri.sales_invoice_item_id
                             WHERE sri.sales_return_id=?
                             ORDER BY sri.line_no");
        $st->execute([$id]);
        $lines = $st->fetchAll() ?: [];

        return [
            'view' => 'sales_return',
            'title' => 'مرتجع بيع',
            'meta' => [
                'no' => (string)($ret['return_no'] ?? ''),
                'date' => (string)substr((string)($ret['return_date'] ?? ''), 0, 10),
                'status' => (string)($ret['status'] ?? ''),
            ],
            'company' => company_profile($pdo),
            'footer' => ['page_hint' => ''],
            'payload' => compact('ret', 'lines'),
        ];
    }

    public function customerReceipt(PDO $pdo, int $id): array
    {
        $st = $pdo->prepare("SELECT cr.*, p.name party_name, COALESCE(p.code, CONCAT('P',LPAD(p.id,5,'0'))) party_code,
                                     cb.name cashbox_name, ba.name bank_account_name
                              FROM customer_receipts cr
                              JOIN parties p ON p.id = COALESCE(cr.party_id, cr.customer_id)
                              LEFT JOIN cashboxes cb ON cb.id=cr.cashbox_id
                              LEFT JOIN bank_accounts ba ON ba.id=cr.bank_account_id
                              WHERE cr.id=? LIMIT 1");
        $st->execute([$id]);
        $receipt = $st->fetch();
        if (!$receipt) {
            throw new RuntimeException('Not found', 404);
        }

        return [
            'view' => 'customer_receipt',
            'title' => 'سند قبض',
            'meta' => [
                'no' => (string)($receipt['receipt_no'] ?? ''),
                'date' => (string)substr((string)($receipt['receipt_date'] ?? ''), 0, 10),
                'title_en' => 'Receipt Voucher',
            ],
            'company' => company_profile($pdo),
            'footer' => [
                'page_hint' => '',
                'note' => 'هذا السند يثبت استلام المبلغ الموضح أعلاه من الطرف المذكور.',
                'signature_style' => 'voucher',
                'signatures' => [
                    ['label' => 'توقيع مسؤول الخزينة'],
                    ['label' => 'توقيع المستلم'],
                ],
            ],
            'payload' => compact('receipt'),
        ];
    }

    public function cashPayment(PDO $pdo, int $id): array
    {
        $st = $pdo->prepare("SELECT p.*, cb.name cashbox_name, ba.name bank_account_name, s.name party_name, ei.name expense_item_name, ec.name expense_category_name
        FROM cash_payments p
        LEFT JOIN cashboxes cb ON cb.id=p.cashbox_id
        LEFT JOIN bank_accounts ba ON ba.id=p.bank_account_id
        LEFT JOIN parties s ON s.id = COALESCE(p.party_id, p.supplier_id)
        LEFT JOIN expense_items ei ON ei.id = p.expense_item_id
        LEFT JOIN expense_categories ec ON ec.id = ei.category_id
        WHERE p.id=? LIMIT 1");
        $st->execute([$id]);
        $row = $st->fetch();
        if (!$row) {
            throw new RuntimeException('Not found', 404);
        }

        return [
            'view' => 'cash_payment',
            'title' => 'سند صرف',
            'meta' => [
                'no' => (string)($row['voucher_no'] ?? ''),
                'date' => (string)substr((string)($row['voucher_date'] ?? ''), 0, 10),
                'title_en' => 'Payment Voucher',
            ],
            'company' => company_profile($pdo),
            'footer' => [
                'page_hint' => '',
                'note' => 'هذا السند يثبت صرف المبلغ الموضح أعلاه حسب البيان المذكور.',
                'signature_style' => 'voucher',
                'signatures' => [
                    ['label' => 'توقيع مسؤول الخزينة'],
                    ['label' => 'توقيع المستلم'],
                ],
            ],
            'payload' => compact('row'),
        ];
    }

    public function supplierPayment(PDO $pdo, int $id): array
    {
        if (!table_exists($pdo, 'supplier_payments')) {
            throw new RuntimeException('Missing migration', 500);
        }

        $st = $pdo->prepare("SELECT sp.*, s.name supplier_name, COALESCE(s.code, CONCAT('S',LPAD(s.id,5,'0'))) supplier_code
                             FROM supplier_payments sp
                             JOIN parties s ON s.id = sp.supplier_id
                             WHERE sp.id=? LIMIT 1");
        $st->execute([$id]);
        $payment = $st->fetch();
        if (!$payment) {
            throw new RuntimeException('Not found', 404);
        }

        return [
            'view' => 'supplier_payment',
            'title' => 'سند سداد مورد',
            'meta' => [
                'no' => (string)($payment['pay_no'] ?? ''),
                'date' => (string)substr((string)($payment['pay_date'] ?? ''), 0, 10),
                'title_en' => 'Supplier Payment Voucher',
            ],
            'company' => company_profile($pdo),
            'footer' => [
                'note' => 'هذا السند يثبت سداد المبلغ الموضح أعلاه للمورد المذكور.',
                'signature_style' => 'voucher',
                'signatures' => [
                    ['label' => 'توقيع مسؤول الخزينة'],
                    ['label' => 'توقيع المستلم'],
                ],
            ],
            'payload' => compact('payment'),
        ];
    }

    public function quotation(PDO $pdo, int $id): array
    {
        QuotationSchemaSupport::ensureQuotationsSchema($pdo);
        $st = $pdo->prepare("SELECT q.*, p.name party_name, p.phone party_phone, p.email party_email FROM quotations q JOIN parties p ON p.id=q.party_id WHERE q.id=? LIMIT 1");
        $st->execute([$id]);
        $quotation = $st->fetch();
        if (!$quotation) {
            throw new RuntimeException('Quotation not found', 404);
        }

        $st = $pdo->prepare("SELECT qi.*, i.name item_name, i.barcode FROM quotation_items qi LEFT JOIN items i ON i.id=qi.item_id WHERE qi.quotation_id=? ORDER BY qi.id ASC");
        $st->execute([$id]);
        $lines = $st->fetchAll() ?: [];

        return [
            'view' => 'quotation',
            'title' => 'عرض سعر',
            'meta' => [
                'no' => (string)$quotation['quotation_no'],
                'date' => (string)$quotation['quotation_date'],
                'title_en' => 'Quotation',
                'valid_until' => (string)($quotation['valid_until'] ?? ''),
            ],
            'company' => company_profile($pdo),
            'footer' => [
                'page_hint' => '',
                'note' => 'هذا العرض صالح حسب التاريخ الموضح أعلاه ما لم يتم إصدار نسخة أحدث.',
                'signatures' => [],
            ],
            'print_template' => 'quotation_v2',
            'payload' => compact('quotation', 'lines'),
        ];
    }
}
