<?php

require_once __DIR__ . '/../../core/database.php';
require_once __DIR__ . '/../../core/config.php';
require_once __DIR__ . '/BillingHelpers.php';
require_once __DIR__ . '/BillingPaymentTermsService.php';

class BillingDraftPayloadFactory
{
    private $pdo;
    private $paymentTerms;

    public function __construct(?PDO $pdo = null)
    {
        $this->pdo = $pdo ?: db();
        $this->paymentTerms = new BillingPaymentTermsService();
    }

    public function build(array $quote, array $customer, array $documentType, array $calculation, array $options = array())
    {
        $settings = $this->loadCompanySettings();
        $environment = billing_normalize_environment($options['environment'] ?? null);
        $factoConfig = function_exists('icylab_facto_config') ? icylab_facto_config($environment) : array('account_id' => '');
        $issueDate = $this->cleanDate($options['issue_date'] ?? date('Y-m-d'));
        $paymentConditions = $this->paymentTerms->normalizeToFacto(
            $options['payment_terms'] ?? ($customer['facto_payment_term'] ?? ($customer['payment_terms'] ?? '0')),
            $options['custom_payment_days'] ?? null
        );
        $roundAsClp = $this->shouldRoundAsClp($documentType, $options);

        $header = array(
            'account_id' => (int) ($factoConfig['account_id'] ?? 0),
            'document_type_id' => (int) $documentType['facto_document_type_id'],
            'received_issued_flag' => 1,
            'issue_date' => $issueDate,
            'issuer_tax_id_code' => billing_clean_rut($settings['company_tax_id'] ?? ''),
            'issuer_tax_id_type' => 'CL-RUT',
            'issuer_legal_name' => $settings['company_name'] ?? '',
            'issuer_address' => $settings['company_address'] ?? '',
            'issuer_district' => $settings['company_comuna'] ?? '',
            'issuer_city' => $settings['company_ciudad'] ?? '',
            'issuer_country_id' => 253,
            'issuer_phone' => $settings['company_phone'] ?? '',
            'issuer_activity' => $settings['company_giro'] ?? '',
            'receiver_tax_id_code' => $this->receiverTaxId($customer, $documentType, $options),
            'receiver_tax_id_type' => $this->receiverTaxType($customer, $documentType, $options),
            'receiver_legal_name' => trim((string)($options['receiver_legal_name'] ?? $this->receiverLegalName($customer))),
            'receiver_address' => trim((string)($options['receiver_address'] ?? ($customer['address'] ?? ''))),
            'receiver_district' => trim((string)($options['receiver_district'] ?? ($customer['district'] ?? ''))),
            'receiver_city' => trim((string)($options['receiver_city'] ?? ($customer['city'] ?? ''))),
            'receiver_country_id' => $this->receiverCountryId($customer, $documentType, $options),
            'receiver_phone' => trim((string)($options['receiver_phone'] ?? ($customer['phone'] ?? ''))),
            'receiver_activity' => trim((string)($options['receiver_activity'] ?? ($customer['business_activity'] ?? ''))),
            'receiver_email' => trim((string)($options['receiver_email'] ?? ($customer['email_dte'] ?: ($customer['email'] ?? '')))),
            'payment_conditions' => $paymentConditions,
            'observations' => 'ICYLAB OS - ' . ($quote['quote_number'] ?? ('Cotizacion ' . ($quote['id'] ?? '')))
        );

        if ((int) $documentType['is_export'] === 1) {
            $header['currency_id'] = $this->currencyId($options['currency_code'] ?? 'USD');
            if (($options['currency_code'] ?? 'USD') !== 'CLP') {
                $header['exchange_rate_value'] = (float) ($options['exchange_rate_value'] ?? 0);
            }
            $header['sale_modality'] = (int) ($options['sale_modality'] ?? 1);
            $header['sale_clause'] = (int) ($options['sale_clause'] ?? 6);
            if (!empty($options['port_embarkation'])) {
                $header['port_embarkation'] = trim((string) $options['port_embarkation']);
            }
            if (!empty($options['port_disembarkation'])) {
                $header['port_disembarkation'] = trim((string) $options['port_disembarkation']);
            }
        }

        if ($documentType['document_family'] === 'dispatch_guide') {
            $header['guide_type'] = (int) ($options['guide_type'] ?? 1);
            $header['transfer_type'] = (int) ($options['transfer_type'] ?? 2);
            if (!empty($options['shipping_address'])) {
                $header['shipping_address'] = trim((string) $options['shipping_address']);
            }
        }

        $details = array();
        foreach ($calculation['lines'] as $line) {
            $lineTaxAmount = $this->factoAmount($line['tax_amount'], $roundAsClp);
            $lineGrossAmount = $this->factoAmount($line['gross_amount'], $roundAsClp);

            $detail = array(
                'quantity' => (float) $line['quantity'],
                'sku' => (string) $line['sku'],
                'line_description' => billing_safe_substr($line['name'], 100),
                'unit_measure' => (string) $line['unit_measure'],
                'unit_price' => $this->factoAmount($line['unit_price'], $roundAsClp),
                'long_description' => (string) $line['description'],
                'total_taxes' => $lineTaxAmount,
                'total_amount_line' => $lineGrossAmount
            );

            if ($line['line_discount_amount'] > 0) {
                $detail['modifier_amount'] = -1 * $this->factoAmount($line['line_discount_amount'], $roundAsClp);
            }

            if ($lineTaxAmount > 0) {
                $detail['taxes'] = array(array(
                    'tax_type_id' => $this->ivaTaxTypeId(),
                    'tax_percentage' => (float) $line['tax_rate'],
                    'tax_amount' => $lineTaxAmount
                ));
            }

            $details[] = $detail;
        }

        $globals = array();
        if ($calculation['global_discount_amount'] > 0) {
            if ($calculation['discount_on_taxable'] > 0) {
                $globals[] = array(
                    'discount_surcharge_code' => 'DA',
                    'discount_surcharge_value' => $this->factoAmount($calculation['discount_on_taxable'], $roundAsClp),
                    'discount_surcharge_type' => '$'
                );
            }
            if ($calculation['discount_on_exempt'] > 0) {
                $globals[] = array(
                    'discount_surcharge_code' => 'DE',
                    'discount_surcharge_value' => $this->factoAmount($calculation['discount_on_exempt'], $roundAsClp),
                    'discount_surcharge_type' => '$'
                );
            }
        }

        $payload = array(
            'options' => array(
                'rounding_type' => 'net',
                'draft_preview' => true,
                // La entrega por email es una accion posterior e independiente.
                // Evita que una falla OAuth del correo FACTO invalide una emision
                // tributaria que ya recibio document_id y folio.
                'send_email' => 0
            ),
            'header' => $header,
            'details' => $details,
            'totals' => array(
                'net_amount' => $this->factoAmount($calculation['net_amount'], $roundAsClp),
                'taxes_amount' => $this->factoAmount($calculation['taxes_amount'], $roundAsClp),
                'total_amount' => $this->factoAmount($calculation['total_amount'], $roundAsClp)
            )
        );

        if (!empty($globals)) {
            $payload['globals_discounts_surcharges'] = $globals;
        }

        if (!empty($options['source_facto_document_id']) && in_array($documentType['document_family'], array('credit_note', 'debit_note'), true)) {
            $payload['references'][] = array(
                'reference_document_id' => (int) $options['source_facto_document_id'],
                'reference_code' => (int) ($options['reference_code'] ?? 1),
                'description' => trim((string) ($options['reference_description'] ?? 'Referencia documento original'))
            );
        }

        $purchaseOrderNumber = trim((string)($options['purchase_order_number'] ?? ''));
        if ($purchaseOrderNumber !== '' && !in_array($documentType['document_family'], array('credit_note', 'debit_note'), true)) {
            $payload['references'][] = array(
                'document_type_id' => '801',
                'reference_number' => $purchaseOrderNumber,
                'reference_code' => 5,
                'reference_date' => $this->cleanDate($options['purchase_order_date'] ?? $issueDate),
                'description' => 'Orden de compra'
            );
        }

        return $payload;
    }


    private function shouldRoundAsClp(array $documentType, array $options)
    {
        if ((int) ($documentType['is_export'] ?? 0) === 1) {
            $currencyCode = strtoupper(trim((string) ($options['currency_code'] ?? 'USD')));
            return $currencyCode === 'CLP';
        }

        return true;
    }

    private function factoAmount($value, $roundAsClp)
    {
        if ($roundAsClp) {
            return (int) round((float) $value, 0);
        }

        return round((float) $value, 2);
    }

    private function ivaTaxTypeId()
    {
        if (defined('ICYLAB_FACTO_CHILE_IVA_TAX_TYPE_ID') && ICYLAB_FACTO_CHILE_IVA_TAX_TYPE_ID !== '') {
            return (string) ICYLAB_FACTO_CHILE_IVA_TAX_TYPE_ID;
        }

        return '387';
    }

    private function loadCompanySettings()
    {
        $stmt = $this->pdo->query('SELECT * FROM system_settings WHERE id = 1 LIMIT 1');
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        return $row ?: array();
    }

    private function cleanDate($value)
    {
        $ts = strtotime((string) $value);
        return $ts ? date('Y-m-d', $ts) : date('Y-m-d');
    }

    private function receiverLegalName(array $customer)
    {
        if (!empty($customer['legal_name'])) {
            return $customer['legal_name'];
        }
        if (!empty($customer['commercial_name'])) {
            return $customer['commercial_name'];
        }
        return $customer['customer_name'] ?? '';
    }

    private function receiverTaxId(array $customer, array $documentType, array $options)
    {
        if ((int)$documentType['is_export'] === 1) {
            $override = trim((string)($options['receiver_tax_id_code'] ?? ''));
            if ($override !== '') return $override;
            if (!empty($customer['export_tax_id_code'])) return $customer['export_tax_id_code'];
        }
        return billing_clean_rut($customer['customer_tax_id'] ?? '');
    }

    private function receiverTaxType(array $customer, array $documentType, array $options)
    {
        if ((int)$documentType['is_export'] === 1) {
            $override = trim((string)($options['receiver_tax_id_type'] ?? ''));
            if ($override !== '') return $override;
            if (!empty($customer['export_tax_id_type'])) return $customer['export_tax_id_type'];
        }
        return !empty($customer['tax_id_type']) ? $customer['tax_id_type'] : 'CL-RUT';
    }

    private function receiverCountryId(array $customer, array $documentType, array $options)
    {
        if (!empty($options['receiver_country_id'])) {
            return (int) $options['receiver_country_id'];
        }
        if ((int) $documentType['is_export'] === 1 && !empty($customer['export_country_id'])) {
            return (int) $customer['export_country_id'];
        }
        if (!empty($customer['country_id'])) {
            return (int) $customer['country_id'];
        }
        return 253;
    }

    private function currencyId($currencyCode)
    {
        $currencyCode = strtoupper(trim((string) $currencyCode));
        $stmt = $this->pdo->prepare('SELECT facto_currency_id FROM billing_currencies WHERE currency_code = ? AND is_active = 1 LIMIT 1');
        $stmt->execute(array($currencyCode));
        $id = $stmt->fetchColumn();
        return $id ? (int) $id : 5;
    }
}
