<?php

declare(strict_types=1);

namespace CloudXM\NFe\Services;

use CloudXM\NFe\Config\Configuration;
use CloudXM\NFe\Persistence\NfeEmissionsRepository;
use CloudXM\SDK\Support\HasLogger;

/**
 * Processes inbound webhook payloads from the NFe server.
 *
 * Handles:
 *  - invoice.issued   → update emission, download files, fire WC action
 *  - invoice.failed   → update emission, add order note, fire WC action
 *  - invoice.scheduled → update emission with scheduled data, store allowed actions
 *  - unknown events   → log and return silently
 */
class NFeWebhookProcessorService
{
    use HasLogger;

    public function __construct(
        private NfeEmissionsRepository $emissionRepo,
        private NFeFileStorageService $fileStorage,
        private ApiClient $apiClient,
        private NFeHistoryService $historyService,
        private Configuration $config
    ) {}

    // -------------------------------------------------------------------------
    // Task 12.2 — dispatch on event_type
    // -------------------------------------------------------------------------

    public function process(array $payload): void
    {
        $eventType = $payload['event_type'] ?? '';

        switch ($eventType) {
            case 'invoice.issued':
                $this->handleIssued($payload);
                break;

            case 'invoice.failed':
                $this->handleFailed($payload);
                break;

            case 'invoice.scheduled':
                $this->handleScheduled($payload);
                break;

            default:
                $this->log()->info('nfe.webhook_unknown_event', ['event_type' => $eventType]);
                break;
        }
    }

    // -------------------------------------------------------------------------
    // Task 12.3 — handle invoice.issued
    // -------------------------------------------------------------------------

    private function handleIssued(array $payload): void
    {
        $data       = $payload['data'] ?? [];
        $invoiceId  = $data['id'] ?? null;

        if (! $invoiceId) {
            $this->log()->warning('nfe.webhook_issued_missing_id', ['payload' => $payload]);
            return;
        }

        $emission = $this->emissionRepo->findByInvoiceId((string) $invoiceId);

        if (! $emission) {
            $this->log()->warning('nfe.webhook_issued_emission_not_found', ['invoice_id' => $invoiceId]);
            return;
        }

        $emissionId = (int) $emission['id'];
        $orderId    = (int) $emission['order_id'];

        // Extract actual issuance timestamp from the server payload.
        // API dates are ISO 8601 with timezone offset (e.g. 2026-04-22T21:19:30-03:00).
        // When offset is present, PHP uses it (ignoring the explicit param).
        // When offset is absent, the explicit param is used as fallback.
        // Parse as WP timezone so that dates without offset are treated as local time.
        $emissionUpdateData = ['status' => 'issued'];
        if (!empty($data['dps_number'])) {
            $emissionUpdateData['dps_number'] = (string) $data['dps_number'];
        }
        if (!empty($data['nfse']['protocol'])) {
            $emissionUpdateData['protocol_number'] = (string) $data['nfse']['protocol'];
        }
        $issuedAt = $data['lifecycle']['issued_at'] ?? null;
        if ($issuedAt) {
            try {
                $dateTime = new \DateTime($issuedAt, new \DateTimeZone($this->config->getScheduleTimezone()));
                $emissionUpdateData['emission_date'] = $dateTime->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s');
            } catch (\Exception $e) {
                $this->log()->warning('nfe.webhook_issued_date_parse_error', [
                    'invoice_id' => $invoiceId,
                    'issued_at' => $issuedAt,
                    'error' => $e->getMessage(),
                ]);
            }
        }

        // Update emission status and date
        $this->emissionRepo->update($emissionId, $emissionUpdateData);

        // Update WC order meta
        $order = wc_get_order($orderId);
        if ($order) {
            $accessKey = $data['access_key'] ?? $data['nfse']['access_key'] ?? '';
            $order->update_meta_data('_cloudxm_nfe_status', 'issued');
            $order->update_meta_data('_cloudxm_nfe_emission_status', 'issued');
            $order->update_meta_data('_cloudxm_nfe_access_key', $accessKey);
            $order->update_meta_data('_cloudxm_nfe_number', $data['number'] ?? $data['nfse']['number'] ?? '');
            $order->update_meta_data('_cloudxm_nfe_series', $data['series'] ?? $data['nfse']['series'] ?? '');
            $order->update_meta_data('_cloudxm_nfe_protocol', $data['nfse']['protocol'] ?? '');
            if (!empty($data['dps_number'])) {
                $order->update_meta_data('_cloudxm_nfe_dps_number', (string) $data['dps_number']);
            }
            if ($issuedAt) {
                $order->update_meta_data('_cloudxm_nfe_issuance_date', $issuedAt);
            }
            $order->delete_meta_data('_cloudxm_nfe_scheduled_at');
            $order->save();

            // Download and store PDF / XML
            $this->downloadAndStoreFiles($invoiceId, $accessKey, $order);

            $order->add_order_note(
                sprintf(
                    __('NFe emitida. Chave de acesso: %s', 'woocommerce-cloudxm-nfe'),
                    $accessKey
                )
            );
        }

        do_action('cloudxm_nfe_invoice_emitted', $orderId, $emissionId);

        $this->log()->info('nfe.webhook_issued_processed', [
            'invoice_id'  => $invoiceId,
            'emission_id' => $emissionId,
            'order_id'    => $orderId,
        ]);
    }

    // -------------------------------------------------------------------------
    // Task 12.4 — handle invoice.failed
    // -------------------------------------------------------------------------

    private function handleFailed(array $payload): void
    {
        $data      = $payload['data'] ?? [];
        $invoiceId = $data['id'] ?? null;

        if (! $invoiceId) {
            $this->log()->warning('nfe.webhook_failed_missing_id', ['payload' => $payload]);
            return;
        }

        $emission = $this->emissionRepo->findByInvoiceId((string) $invoiceId);

        if (! $emission) {
            $this->log()->warning('nfe.webhook_failed_emission_not_found', ['invoice_id' => $invoiceId]);
            return;
        }

        $emissionId   = (int) $emission['id'];
        $orderId      = (int) $emission['order_id'];
        $errorMessage = $data['error_message'] ?? __('Unknown error', 'woocommerce-cloudxm-nfe');

        $this->emissionRepo->update($emissionId, ['status' => 'failed', 'error_message' => $errorMessage]);

        $order = wc_get_order($orderId);
        if ($order) {
            $order->update_meta_data('_cloudxm_nfe_status', 'failed');
            $order->update_meta_data('_cloudxm_nfe_emission_status', 'failed');
            $order->update_meta_data('_cloudxm_nfe_error', $errorMessage);
            $order->save();
            $order->add_order_note(
                sprintf(
                    __('NFe falhou: %s', 'woocommerce-cloudxm-nfe'),
                    $errorMessage
                )
            );
        }

        do_action('cloudxm_nfe_invoice_failed', $orderId, $emissionId, $errorMessage);

        $this->log()->warning('nfe.webhook_failed_processed', [
            'invoice_id'  => $invoiceId,
            'emission_id' => $emissionId,
            'order_id'    => $orderId,
            'error'       => $errorMessage,
        ]);
    }

    // -------------------------------------------------------------------------
    // Task 12.5 — handle invoice.scheduled
    // -------------------------------------------------------------------------

    private function handleScheduled(array $payload): void
    {
        $data      = $payload['data'] ?? [];
        $invoiceId = $data['id'] ?? null;

        if (! $invoiceId) {
            $this->log()->warning('nfe.webhook_scheduled_missing_id', ['payload' => $payload]);
            return;
        }

        $emission = $this->emissionRepo->findByInvoiceId((string) $invoiceId);

        if (! $emission) {
            $this->log()->warning('nfe.webhook_scheduled_emission_not_found', ['invoice_id' => $invoiceId]);
            return;
        }

        $emissionId = (int) $emission['id'];
        $orderId    = (int) $emission['order_id'];

        // Extract scheduled data from lifecycle
        $lifecycle = $data['lifecycle'] ?? [];
        $scheduledFor = $lifecycle['scheduled_for'] ?? null;
        $scheduledForLocal = $lifecycle['scheduled_for_local'] ?? null;

        // Extract allowed actions
        $allowedActions = $data['allowed_actions'] ?? [];

        // Update emission with scheduled data
        $updateData = [
            'status' => 'scheduled',
            'scheduled_for' => $scheduledFor,
            'scheduled_for_local' => $scheduledForLocal,
            'allowed_actions' => json_encode($allowedActions),
        ];

        $this->emissionRepo->update($emissionId, $updateData);

        // Update WC order meta
        $order = wc_get_order($orderId);
        if ($order) {
            $order->update_meta_data('_cloudxm_nfe_status', 'scheduled');
            $order->update_meta_data('_cloudxm_nfe_emission_status', 'scheduled');
            if ($scheduledForLocal) {
                $order->update_meta_data('_cloudxm_nfe_scheduled_at', $scheduledForLocal);
            }
            $order->save();

            $scheduledDisplay = $scheduledForLocal
                ? date_i18n(get_option('date_format') . ' ' . get_option('time_format'), strtotime($scheduledForLocal))
                : __('N/A', 'woocommerce-cloudxm-nfe');

            $order->add_order_note(
                sprintf(
                    __('NFe agendada para emissão em: %s', 'woocommerce-cloudxm-nfe'),
                    $scheduledDisplay
                )
            );
        }

        do_action('cloudxm_nfe_invoice_scheduled', $orderId, $emissionId);

        $this->log()->info('nfe.webhook_scheduled_processed', [
            'invoice_id'  => $invoiceId,
            'emission_id' => $emissionId,
            'order_id'    => $orderId,
            'scheduled_for' => $scheduledFor,
            'allowed_actions' => $allowedActions,
        ]);
    }

    // -------------------------------------------------------------------------
    // Helpers
    // -------------------------------------------------------------------------

    private function downloadAndStoreFiles(string $invoiceId, string $accessKey, \WC_Order $order): void
    {
        $emissionDate = new \DateTime();

        try {
            $pdf = $this->apiClient->downloadPdfV2($invoiceId);
            if (! empty($pdf)) {
                $this->fileStorage->storePdf($invoiceId, $pdf, $accessKey, $emissionDate);
            }
        } catch (\Throwable $e) {
            $this->log()->warning('nfe.webhook_pdf_download_failed', [
                'invoice_id' => $invoiceId,
                'error'      => $e->getMessage(),
            ]);
        }

        try {
            $xml = $this->apiClient->downloadXmlV2($invoiceId);
            if (! empty($xml)) {
                $this->fileStorage->storeXml($invoiceId, $xml, $accessKey, $emissionDate);
            }
        } catch (\Throwable $e) {
            $this->log()->warning('nfe.webhook_xml_download_failed', [
                'invoice_id' => $invoiceId,
                'error'      => $e->getMessage(),
            ]);
        }
    }
}
