<?php

declare(strict_types=1);

namespace App\Services;

use InvalidArgumentException;
use PDO;

final class PrintSettingsService
{
    private const TEMPLATE_KEYS = ['standard', 'compact', 'formal'];

    private const DOCUMENTS = [
        'quotation' => ['label' => 'عرض السعر', 'allowed_formats' => ['a4']],
        'sales_invoice' => ['label' => 'فاتورة البيع', 'allowed_formats' => ['a4', 'receipt']],
        'purchase_invoice' => ['label' => 'فاتورة الشراء', 'allowed_formats' => ['a4', 'receipt']],
        'sales_return' => ['label' => 'مرتجع البيع', 'allowed_formats' => ['a4', 'receipt']],
        'purchase_return' => ['label' => 'مرتجع الشراء', 'allowed_formats' => ['a4', 'receipt']],
        'customer_receipt' => ['label' => 'سند القبض', 'allowed_formats' => ['a4', 'receipt']],
        'cash_payment' => ['label' => 'سند الصرف', 'allowed_formats' => ['a4', 'receipt']],
        'supplier_payment' => ['label' => 'سند سداد المورد', 'allowed_formats' => ['a4', 'receipt']],
        'party_statement' => ['label' => 'كشف الحساب', 'allowed_formats' => ['a4']],
        'check' => ['label' => 'شيك', 'allowed_formats' => ['a4']],
        'customer_card' => ['label' => 'بيانات عميل', 'allowed_formats' => ['a4']],
        'supplier_card' => ['label' => 'بيانات مورد', 'allowed_formats' => ['a4']],
    ];

    public function __construct(private PDO $pdo)
    {
    }

    public function settings(): array
    {
        ensure_app_settings_schema($this->pdo);

        $settings = [
            'pos_default_print_format' => $this->get('pos_default_print_format', 'receipt'),
            'barcode_label_width_mm' => $this->get('barcode_label_width_mm', '50'),
            'barcode_label_height_mm' => $this->get('barcode_label_height_mm', '30'),
            'barcode_show_price' => $this->get('barcode_show_price', '1'),
            'barcode_show_item_name' => $this->get('barcode_show_item_name', '1'),
            'documents' => [],
            'document_definitions' => self::documentDefinitions(),
        ];

        foreach (self::DOCUMENTS as $key => $definition) {
            $settings['documents'][$key] = $this->documentSettings($key);
        }

        return $settings;
    }


    public function saveGeneral(array $input): void
    {
        ensure_app_settings_schema($this->pdo);

        $format = strtolower(trim((string)($input['pos_default_print_format'] ?? 'receipt')));
        if (!in_array($format, ['receipt', 'a4'], true)) {
            throw new InvalidArgumentException('صيغة طباعة POS غير صحيحة.');
        }

        $width = $this->normalizeMm($input['barcode_label_width_mm'] ?? '50', 50.0);
        $height = $this->normalizeMm($input['barcode_label_height_mm'] ?? '30', 30.0);

        $this->set('pos_default_print_format', $format);
        $this->set('barcode_label_width_mm', $width);
        $this->set('barcode_label_height_mm', $height);
        $this->set('barcode_show_price', !empty($input['barcode_show_price']) ? '1' : '0');
        $this->set('barcode_show_item_name', !empty($input['barcode_show_item_name']) ? '1' : '0');
    }

    public function saveDocument(string $documentKey, array $input): void
    {
        ensure_app_settings_schema($this->pdo);

        $definition = self::DOCUMENTS[$documentKey] ?? null;
        if ($definition === null) {
            throw new InvalidArgumentException('نوع مستند الطباعة غير معروف.');
        }

        $docInput = is_array($input['document'] ?? null) ? $input['document'] : [];
        $allowedFormats = $definition['allowed_formats'];
        $defaultFormat = strtolower(trim((string)($docInput['default_format'] ?? ($allowedFormats[0] ?? 'a4'))));
        if (!in_array($defaultFormat, $allowedFormats, true)) {
            $defaultFormat = $allowedFormats[0] ?? 'a4';
        }

        $this->set($this->docSettingKey($documentKey, 'default_format'), $defaultFormat);
        $this->set($this->docSettingKey($documentKey, 'show_logo'), !empty($docInput['show_logo']) ? '1' : '0');
        $this->set($this->docSettingKey($documentKey, 'show_signatures'), !empty($docInput['show_signatures']) ? '1' : '0');
        $this->set($this->docSettingKey($documentKey, 'show_terms'), !empty($docInput['show_terms']) ? '1' : '0');
        $this->set($this->docSettingKey($documentKey, 'show_tax_no'), !empty($docInput['show_tax_no']) ? '1' : '0');
        $this->set($this->docSettingKey($documentKey, 'footer_note'), trim((string)($docInput['footer_note'] ?? '')));

        $templateProfiles = $this->normalizeTemplateProfiles($documentKey, is_array($docInput['templates'] ?? null) ? $docInput['templates'] : []);
        $this->set($this->docSettingKey($documentKey, 'template_profiles_json'), json_encode($templateProfiles, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

        $activeTemplate = strtolower(trim((string)($docInput['active_template'] ?? 'standard')));
        if (!isset($templateProfiles[$activeTemplate])) {
            $activeTemplate = 'standard';
        }
        $this->set($this->docSettingKey($documentKey, 'active_template'), $activeTemplate);
    }

    public function save(array $input): void
    {
        $this->saveGeneral($input);

        $documentsInput = is_array($input['documents'] ?? null) ? $input['documents'] : [];
        foreach (array_keys(self::DOCUMENTS) as $key) {
            $this->saveDocument($key, ['document' => is_array($documentsInput[$key] ?? null) ? $documentsInput[$key] : []]);
        }
    }

    public function posDefaultPrintFormat(): string
    {
        $format = strtolower(trim((string)$this->get('pos_default_print_format', 'receipt')));
        return in_array($format, ['receipt', 'a4'], true) ? $format : 'receipt';
    }

    public function documentSettings(string $documentKey): array
    {
        ensure_app_settings_schema($this->pdo);

        $definition = self::DOCUMENTS[$documentKey] ?? null;
        if ($definition === null) {
            throw new InvalidArgumentException('نوع مستند الطباعة غير معروف.');
        }

        $allowedFormats = $definition['allowed_formats'];
        $defaultFormat = strtolower(trim((string)$this->get($this->docSettingKey($documentKey, 'default_format'), $allowedFormats[0] ?? 'a4')));
        if (!in_array($defaultFormat, $allowedFormats, true)) {
            $defaultFormat = $allowedFormats[0] ?? 'a4';
        }

        $templates = $this->templateProfiles($documentKey);
        $activeTemplate = strtolower(trim((string)$this->get($this->docSettingKey($documentKey, 'active_template'), 'standard')));
        if (!isset($templates[$activeTemplate])) {
            $activeTemplate = 'standard';
        }

        return [
            'key' => $documentKey,
            'label' => $definition['label'],
            'allowed_formats' => $allowedFormats,
            'default_format' => $defaultFormat,
            'show_logo' => $this->get($this->docSettingKey($documentKey, 'show_logo'), '1') === '1',
            'show_signatures' => $this->get($this->docSettingKey($documentKey, 'show_signatures'), '1') === '1',
            'show_terms' => $this->get($this->docSettingKey($documentKey, 'show_terms'), '1') === '1',
            'show_tax_no' => $this->get($this->docSettingKey($documentKey, 'show_tax_no'), '1') === '1',
            'footer_note' => (string)$this->get($this->docSettingKey($documentKey, 'footer_note'), ''),
            'active_template' => $activeTemplate,
            'templates' => $templates,
            'section_definitions' => self::sectionDefinitions($documentKey),
        ];
    }

    public function preparePrintPayload(string $documentKey, array $payload): array
    {
        $settings = $this->documentSettings($documentKey);
        $company = is_array($payload['company'] ?? null) ? $payload['company'] : [];
        $footer = is_array($payload['footer'] ?? null) ? $payload['footer'] : [];
        $template = $settings['templates'][$settings['active_template']] ?? $settings['templates']['standard'];
        $sections = is_array($template['sections'] ?? null) ? $template['sections'] : [];

        if (!$settings['show_logo']) {
            $company['logo_path'] = '';
        }
        if (!$settings['show_tax_no']) {
            $company['tax_no'] = '';
        }
        if (!$settings['show_signatures']) {
            $footer['signatures'] = [];
            if (isset($sections['footer']['signatures'])) {
                $sections['footer']['signatures']['enabled'] = false;
            }
        }
        if (!$settings['show_terms'] && isset($sections['body']['terms'])) {
            $sections['body']['terms']['enabled'] = false;
        }
        if ($settings['footer_note'] !== '') {
            $footer['note'] = $settings['footer_note'];
        }

        $payload['company'] = $company;
        $payload['footer'] = $footer;
        $payload['print_options'] = [
            'show_logo' => $settings['show_logo'],
            'show_signatures' => $settings['show_signatures'],
            'show_terms' => $settings['show_terms'],
            'show_tax_no' => $settings['show_tax_no'],
            'default_format' => $settings['default_format'],
            'document_label' => $settings['label'],
            'active_template' => $settings['active_template'],
            'active_template_label' => (string)($template['label'] ?? 'القالب القياسي'),
            'template_sections' => $sections,
        ];
        $payload['document_key'] = $documentKey;

        return $payload;
    }

    public function preferredDocumentFormat(string $documentKey, array $allowedFormats): string
    {
        $settings = $this->documentSettings($documentKey);
        $preferred = (string)($settings['default_format'] ?? 'a4');
        return in_array($preferred, $allowedFormats, true) ? $preferred : ($allowedFormats[0] ?? 'a4');
    }

    public static function documentDefinitions(): array
    {
        return self::DOCUMENTS;
    }

    public static function sectionDefinitions(string $documentKey): array
    {
        return match ($documentKey) {
            'quotation' => [
                'header' => [
                    'company_block' => ['label' => 'بيانات الشركة', 'default_title' => 'بيانات الشركة', 'order' => 10],
                    'document_meta' => ['label' => 'بيانات المستند', 'default_title' => 'بيانات العرض', 'order' => 20],
                ],
                'body' => [
                    'party_block' => ['label' => 'بيانات العميل', 'default_title' => 'مقدم إلى', 'order' => 10],
                    'items_table' => ['label' => 'جدول البنود', 'default_title' => 'بنود العرض', 'order' => 20],
                    'totals' => ['label' => 'ملخص الأسعار', 'default_title' => 'ملخص الأسعار', 'order' => 30],
                    'terms' => ['label' => 'الشروط والأحكام', 'default_title' => 'الشروط والأحكام', 'order' => 40],
                ],
                'footer' => [
                    'signatures' => ['label' => 'التوقيعات', 'default_title' => 'التوقيعات', 'order' => 10],
                    'company_strip' => ['label' => 'شريط بيانات الشركة', 'default_title' => 'بيانات الشركة', 'order' => 20],
                    'footer_note' => ['label' => 'النص السفلي', 'default_title' => 'ملاحظات ختامية', 'order' => 30],
                ],
            ],
            'sales_invoice', 'purchase_invoice', 'sales_return', 'purchase_return' => [
                'header' => [
                    'company_block' => ['label' => 'بيانات الشركة', 'default_title' => 'بيانات الشركة', 'order' => 10],
                    'document_meta' => ['label' => 'بيانات المستند', 'default_title' => 'بيانات الفاتورة', 'order' => 20],
                ],
                'body' => [
                    'party_block' => ['label' => 'بيانات العميل/المورد', 'default_title' => 'بيانات الطرف', 'order' => 10],
                    'hero_totals' => ['label' => 'بطاقات الإجمالي', 'default_title' => 'ملخص سريع', 'order' => 20],
                    'items_table' => ['label' => 'جدول البنود', 'default_title' => 'تفاصيل البنود', 'order' => 30],
                    'notes' => ['label' => 'الملاحظات', 'default_title' => 'ملاحظات', 'order' => 40],
                    'totals' => ['label' => 'الملخص المالي', 'default_title' => 'الملخص المالي', 'order' => 50],
                ],
                'footer' => [
                    'signatures' => ['label' => 'التوقيعات', 'default_title' => 'التوقيعات', 'order' => 10],
                    'company_strip' => ['label' => 'شريط بيانات الشركة', 'default_title' => 'بيانات الشركة', 'order' => 20],
                    'footer_note' => ['label' => 'النص السفلي', 'default_title' => 'ملاحظات ختامية', 'order' => 30],
                ],
            ],
            'customer_receipt', 'cash_payment', 'supplier_payment' => [
                'header' => [
                    'company_block' => ['label' => 'بيانات الشركة', 'default_title' => 'بيانات الشركة', 'order' => 10],
                    'document_meta' => ['label' => 'بيانات المستند', 'default_title' => 'بيانات السند', 'order' => 20],
                ],
                'body' => [
                    'party_block' => ['label' => 'بيانات السند', 'default_title' => 'بيانات السند', 'order' => 10],
                    'hero_totals' => ['label' => 'بطاقات القيمة', 'default_title' => 'ملخص سريع', 'order' => 20],
                    'notes' => ['label' => 'البيان/الملاحظات', 'default_title' => 'ملاحظات السند', 'order' => 30],
                    'totals' => ['label' => 'ملخص السند', 'default_title' => 'ملخص السند', 'order' => 40],
                ],
                'footer' => [
                    'signatures' => ['label' => 'التوقيعات', 'default_title' => 'التوقيعات', 'order' => 10],
                    'company_strip' => ['label' => 'شريط بيانات الشركة', 'default_title' => 'بيانات الشركة', 'order' => 20],
                    'footer_note' => ['label' => 'النص السفلي', 'default_title' => 'ملاحظات ختامية', 'order' => 30],
                ],
            ],
            'party_statement' => [
                'header' => [
                    'company_block' => ['label' => 'بيانات الشركة', 'default_title' => 'بيانات الشركة', 'order' => 10],
                    'document_meta' => ['label' => 'بيانات المستند', 'default_title' => 'بيانات الكشف', 'order' => 20],
                ],
                'body' => [
                    'party_block' => ['label' => 'بيانات العميل/المورد', 'default_title' => 'بيانات الطرف', 'order' => 10],
                    'hero_totals' => ['label' => 'بطاقات الرصيد', 'default_title' => 'أرصدة رئيسية', 'order' => 20],
                    'summary_block' => ['label' => 'ملخص الفترة', 'default_title' => 'ملخص الفترة', 'order' => 30],
                    'notes' => ['label' => 'ملاحظات الطباعة', 'default_title' => 'ملاحظات الطباعة', 'order' => 40],
                    'items_table' => ['label' => 'حركة الحساب', 'default_title' => 'حركة الحساب', 'order' => 50],
                    'totals' => ['label' => 'إجمالي الكشف', 'default_title' => 'إجمالي الكشف', 'order' => 60],
                ],
                'footer' => [
                    'signatures' => ['label' => 'التوقيعات', 'default_title' => 'التوقيعات', 'order' => 10],
                    'company_strip' => ['label' => 'شريط بيانات الشركة', 'default_title' => 'بيانات الشركة', 'order' => 20],
                    'footer_note' => ['label' => 'النص السفلي', 'default_title' => 'ملاحظات ختامية', 'order' => 30],
                ],
            ],
            'check', 'customer_card', 'supplier_card' => [
                'header' => [
                    'company_block' => ['label' => 'بيانات الشركة', 'default_title' => 'بيانات الشركة', 'order' => 10],
                    'document_meta' => ['label' => 'بيانات المستند', 'default_title' => 'بيانات المستند', 'order' => 20],
                ],
                'body' => [],
                'footer' => [
                    'signatures' => ['label' => 'التوقيعات', 'default_title' => 'التوقيعات', 'order' => 10],
                    'company_strip' => ['label' => 'شريط بيانات الشركة', 'default_title' => 'بيانات الشركة', 'order' => 20],
                    'footer_note' => ['label' => 'النص السفلي', 'default_title' => 'ملاحظات ختامية', 'order' => 30],
                ],
            ],
            default => [
                'header' => [
                    'company_block' => ['label' => 'بيانات الشركة', 'default_title' => 'بيانات الشركة', 'order' => 10],
                    'document_meta' => ['label' => 'بيانات المستند', 'default_title' => 'بيانات المستند', 'order' => 20],
                ],
                'body' => [
                    'items_table' => ['label' => 'المحتوى الرئيسي', 'default_title' => 'المحتوى الرئيسي', 'order' => 10],
                ],
                'footer' => [
                    'signatures' => ['label' => 'التوقيعات', 'default_title' => 'التوقيعات', 'order' => 10],
                    'footer_note' => ['label' => 'النص السفلي', 'default_title' => 'النص السفلي', 'order' => 20],
                ],
            ],
        };
    }

    public function barcodeLabelWidthMm(): string
    {
        return $this->normalizeMm($this->get('barcode_label_width_mm', '50'), 50.0);
    }

    public function barcodeLabelHeightMm(): string
    {
        return $this->normalizeMm($this->get('barcode_label_height_mm', '30'), 30.0);
    }

    public function barcodeShowPrice(): bool
    {
        return (string)$this->get('barcode_show_price', '1') === '1';
    }

    public function barcodeShowItemName(): bool
    {
        return (string)$this->get('barcode_show_item_name', '1') === '1';
    }

    private function templateProfiles(string $documentKey): array
    {
        $defaults = self::defaultTemplateProfiles($documentKey);
        $raw = (string)$this->get($this->docSettingKey($documentKey, 'template_profiles_json'), '');
        if ($raw === '') {
            return $defaults;
        }

        $decoded = json_decode($raw, true);
        if (!is_array($decoded)) {
            return $defaults;
        }

        return $this->normalizeTemplateProfiles($documentKey, $decoded);
    }

    private static function defaultTemplateProfiles(string $documentKey): array
    {
        $definitions = self::sectionDefinitions($documentKey);
        $profiles = [];
        foreach (self::TEMPLATE_KEYS as $templateKey) {
            $profiles[$templateKey] = [
                'label' => match ($templateKey) {
                    'compact' => 'قالب مختصر',
                    'formal' => 'قالب رسمي',
                    default => 'القالب القياسي',
                },
                'sections' => self::defaultSectionsForTemplate($documentKey, $templateKey, $definitions),
            ];
        }
        return $profiles;
    }

    private static function defaultSectionsForTemplate(string $documentKey, string $templateKey, array $definitions): array
    {
        $sections = [];
        foreach ($definitions as $area => $areaDefs) {
            $sections[$area] = [];
            foreach ($areaDefs as $sectionKey => $sectionDef) {
                $enabled = true;
                $order = (int)($sectionDef['order'] ?? 10);
                $title = (string)($sectionDef['default_title'] ?? ($sectionDef['label'] ?? ''));

                if ($templateKey === 'compact') {
                    if ($area === 'footer' && $sectionKey === 'company_strip') {
                        $enabled = false;
                    }
                    if ($documentKey === 'quotation' && $area === 'body') {
                        if ($sectionKey === 'totals') { $order = 30; }
                        if ($sectionKey === 'terms') { $order = 40; }
                    }
                    if (in_array($documentKey, ['sales_invoice', 'purchase_invoice', 'sales_return', 'purchase_return'], true) && $area === 'body') {
                        if ($sectionKey === 'totals') { $order = 40; }
                        if ($sectionKey === 'notes') { $order = 50; }
                    }
                }

                if ($templateKey === 'formal') {
                    if ($area === 'header') {
                        if ($sectionKey === 'document_meta') { $order = 10; }
                        if ($sectionKey === 'company_block') { $order = 20; }
                    }
                    if ($documentKey === 'quotation' && $area === 'body' && $sectionKey === 'terms') {
                        $title = 'الشروط التجارية';
                    }
                }

                $sections[$area][$sectionKey] = [
                    'enabled' => $enabled,
                    'title' => $title,
                    'order' => $order,
                ];
            }
        }
        return $sections;
    }

    private function normalizeTemplateProfiles(string $documentKey, array $input): array
    {
        $defaults = self::defaultTemplateProfiles($documentKey);
        $definitions = self::sectionDefinitions($documentKey);
        $normalized = [];

        foreach (self::TEMPLATE_KEYS as $templateKey) {
            $templateInput = is_array($input[$templateKey] ?? null) ? $input[$templateKey] : [];
            $base = $defaults[$templateKey];
            $sections = $base['sections'];
            $inputSections = is_array($templateInput['sections'] ?? null) ? $templateInput['sections'] : [];

            foreach ($definitions as $area => $areaDefs) {
                foreach ($areaDefs as $sectionKey => $sectionDef) {
                    $sectionInput = is_array($inputSections[$area][$sectionKey] ?? null) ? $inputSections[$area][$sectionKey] : [];
                    $sections[$area][$sectionKey] = [
                        'enabled' => array_key_exists('enabled', $sectionInput) ? !empty($sectionInput['enabled']) : !empty($sections[$area][$sectionKey]['enabled']),
                        'title' => trim((string)($sectionInput['title'] ?? $sections[$area][$sectionKey]['title'] ?? $sectionDef['default_title'] ?? $sectionDef['label'] ?? '')),
                        'order' => max(1, min(99, (int)($sectionInput['order'] ?? $sections[$area][$sectionKey]['order'] ?? $sectionDef['order'] ?? 10))),
                    ];
                }
            }

            $normalized[$templateKey] = [
                'label' => trim((string)($templateInput['label'] ?? $base['label'])) ?: $base['label'],
                'sections' => $sections,
            ];
        }

        return $normalized;
    }

    private function normalizeMm(mixed $value, float $default): string
    {
        $number = is_numeric($value) ? (float) $value : $default;
        if ($number < 20 || $number > 200) {
            $number = $default;
        }

        $normalized = rtrim(rtrim(number_format($number, 2, '.', ''), '0'), '.');
        return $normalized !== '' ? $normalized : (string) $default;
    }

    private function docSettingKey(string $documentKey, string $field): string
    {
        return 'print_' . $documentKey . '_' . $field;
    }

    private function get(string $key, string $default = ''): string
    {
        $stmt = $this->pdo->prepare('SELECT setting_value FROM app_settings WHERE setting_key = ? LIMIT 1');
        $stmt->execute([$key]);
        $value = $stmt->fetchColumn();
        return $value === false || $value === null ? $default : (string)$value;
    }

    private function set(string $key, string $value): void
    {
        $stmt = $this->pdo->prepare('INSERT INTO app_settings (setting_key, setting_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)');
        $stmt->execute([$key, $value]);
    }
}
