<?php

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

class BillingDraftService
{
    private $pdo;
    private $validator;

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

    public function saveQuoteDraft($quoteId, $documentKey, array $options = array())
    {
        $environment = billing_normalize_environment($options['environment'] ?? 'sandbox');
        $quoteId = (int)$quoteId;
        if ($quoteId <= 0) {
            throw new InvalidArgumentException('Cotizacion no valida.');
        }

        $documentKey = trim((string)$documentKey) ?: 'invoice_electronic';

        $validation = $this->validator->validateQuoteForIssue($quoteId, $documentKey, $options);
        if (empty($validation['idempotency_key'])) {
            $validation['idempotency_key'] = 'quote:' . $quoteId . ':document:' . $documentKey . ':env:' . $environment . ':v1';
        }

        $this->assertNoIssuedDocument($validation['idempotency_key']);

        $payload = !empty($validation['payload_preview']) && is_array($validation['payload_preview'])
            ? $validation['payload_preview']
            : array();

        $payload['_icylab_draft'] = array(
            'quote_id' => $quoteId,
            'document_type_key' => $documentKey,
            'environment' => $environment,
            'issue_date' => $options['issue_date'] ?? date('Y-m-d'),
            'payment_terms_key' => $options['payment_terms'] ?? ($options['payment_terms_key'] ?? ''),
            'saved_at' => date('c')
        );

        $logId = $this->upsertDraftLog($validation, $documentKey, $environment, $payload);

        return array(
            'ok' => true,
            'draft' => array(
                'log_id' => (int)$logId,
                'quote_id' => $quoteId,
                'document_type_key' => $documentKey,
                'environment' => $environment,
                'status' => 'draft',
                'mode' => 'dry_run',
                'has_validation_blocks' => empty($validation['ok']),
                'errors' => isset($validation['errors']) && is_array($validation['errors']) ? $validation['errors'] : array(),
                'warnings' => isset($validation['warnings']) && is_array($validation['warnings']) ? $validation['warnings'] : array(),
                'updated_at' => date('Y-m-d H:i:s')
            ),
            'validation' => $validation,
            'message' => empty($validation['ok'])
                ? 'Borrador tributario guardado con bloqueos pendientes.'
                : 'Borrador tributario guardado correctamente.'
        );
    }

    private function assertNoIssuedDocument($idempotencyKey)
    {
        $stmt = $this->pdo->prepare("SELECT id, facto_document_id, document_number FROM billing_issue_logs WHERE idempotency_key = ? AND mode = 'issue' AND status IN ('sent','success','pending_reconcile') LIMIT 1");
        $stmt->execute(array($idempotencyKey));
        if ($stmt->fetch(PDO::FETCH_ASSOC)) {
            throw new RuntimeException('Ya existe un documento emitido o pendiente de conciliacion para esta cotizacion.');
        }
    }

    private function upsertDraftLog(array $validation, $documentKey, $environment, array $payload)
    {
        $quote = $validation['quote'] ?? array('id' => null);
        $customer = $validation['customer'] ?? array('id' => null);
        $documentType = $validation['document_type'] ?? array('facto_document_type_id' => null);
        $errors = isset($validation['errors']) && is_array($validation['errors']) ? $validation['errors'] : array();
        $errorMessage = empty($errors) ? null : implode(' | ', $errors);
        $userId = function_exists('current_user_id') ? (int)current_user_id() : 0;

        $stmt = $this->pdo->prepare("\n            INSERT INTO billing_issue_logs\n            (quote_id, opportunity_id, customer_id, document_type_key, document_type_id, environment, mode, status, idempotency_key, request_payload, response_payload, http_code, error_code, error_message, created_by)\n            VALUES\n            (?, ?, ?, ?, ?, ?, 'dry_run', 'draft', ?, ?, ?, NULL, ?, ?, ?)\n            ON DUPLICATE KEY UPDATE\n                quote_id = VALUES(quote_id),\n                opportunity_id = VALUES(opportunity_id),\n                customer_id = VALUES(customer_id),\n                document_type_key = VALUES(document_type_key),\n                document_type_id = VALUES(document_type_id),\n                environment = VALUES(environment),\n                mode = 'dry_run',\n                status = 'draft',\n                request_payload = VALUES(request_payload),\n                response_payload = VALUES(response_payload),\n                http_code = NULL,\n                error_code = VALUES(error_code),\n                error_message = VALUES(error_message),\n                updated_at = CURRENT_TIMESTAMP\n        ");

        $stmt->execute(array(
            isset($quote['id']) ? (int)$quote['id'] : null,
            isset($quote['opportunity_id']) ? (int)$quote['opportunity_id'] : null,
            isset($customer['id']) ? (int)$customer['id'] : null,
            $documentKey,
            isset($documentType['facto_document_type_id']) ? (int)$documentType['facto_document_type_id'] : null,
            $environment,
            $validation['idempotency_key'],
            $this->jsonEncode($payload),
            $this->jsonEncode($validation),
            empty($validation['ok']) ? 'VALIDATION_BLOCKED' : null,
            $errorMessage,
            $userId ?: null
        ));

        $stmt = $this->pdo->prepare('SELECT id FROM billing_issue_logs WHERE idempotency_key = ? LIMIT 1');
        $stmt->execute(array($validation['idempotency_key']));
        return (int)$stmt->fetchColumn();
    }

    private function jsonEncode($value)
    {
        $json = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        return $json === false ? null : $json;
    }
}
