<?php

declare(strict_types=1);

namespace CloudXM\NFe\Providers;

use CloudXM\NFe\Bootstrap\Container;
use CloudXM\NFe\Config\Configuration;

/**
 * Core Service Provider
 *
 * Registers core services
 */
class CoreServiceProvider
{
    public function __construct(
        private Container $container
    ) {}

    /**
     * Register core services
     */
    public function register(): void
    {
        // Register Configuration (no dependencies)
        $this->container->singleton(\CloudXM\NFe\Config\Configuration::class);
        $this->container->singleton(\CloudXM\SDK\Contracts\ConfigurationInterface::class, function ($c) {
            return $c->get(\CloudXM\NFe\Config\Configuration::class);
        });

        // Register API Client (depends on Configuration)
        $this->container->singleton(\CloudXM\NFe\Services\ApiClient::class, function ($c) {
            return new \CloudXM\NFe\Services\ApiClient(
                $c->get(\CloudXM\NFe\Config\Configuration::class)
            );
        });

        // Register Tenant Config Cache (depends on Configuration and ApiClient)
        $this->container->singleton(\CloudXM\NFe\Services\TenantConfigCache::class, function ($c) {
            return new \CloudXM\NFe\Services\TenantConfigCache(
                $c->get(\CloudXM\NFe\Config\Configuration::class),
                $c->get(\CloudXM\NFe\Services\ApiClient::class)
            );
        });

        // Register Order Mapper V2 (depends on Configuration and TenantConfigCache)
        $this->container->singleton(\CloudXM\NFe\Services\OrderMapperV2::class, function ($c) {
            return new \CloudXM\NFe\Services\OrderMapperV2(
                $c->get(\CloudXM\NFe\Config\Configuration::class),
                $c->get(\CloudXM\NFe\Services\TenantConfigCache::class)
            );
        });

        // Register NFe File Storage Service (depends on Configuration and ApiClient)
        $this->container->singleton(\CloudXM\NFe\Services\NFeFileStorageService::class, function ($c) {
            return new \CloudXM\NFe\Services\NFeFileStorageService(
                $c->get(\CloudXM\NFe\Config\Configuration::class),
                $c->get(\CloudXM\NFe\Services\ApiClient::class)
            );
        });

        // Register NFe Emissions Repository (no dependencies)
        $this->container->singleton(\CloudXM\NFe\Persistence\NfeEmissionsRepository::class, function ($c) {
            return new \CloudXM\NFe\Persistence\NfeEmissionsRepository(
                $c->get(\CloudXM\NFe\Config\Configuration::class)->getTablePrefix()
            );
        });

        // Register NFe History Repository (no dependencies)
        $this->container->singleton(\CloudXM\NFe\Persistence\NfeHistoryRepository::class, function ($c) {
            return new \CloudXM\NFe\Persistence\NfeHistoryRepository(
                $c->get(\CloudXM\NFe\Config\Configuration::class)->getTablePrefix()
            );
        });

        // Register NFe Queue Repository (no dependencies)
        $this->container->singleton(\CloudXM\NFe\Persistence\NfeQueueRepository::class, function ($c) {
            return new \CloudXM\NFe\Persistence\NfeQueueRepository(
                $c->get(\CloudXM\NFe\Config\Configuration::class)->getTablePrefix()
            );
        });

        // Register NFe History Service (depends on NfeHistoryRepository)
        $this->container->singleton(\CloudXM\NFe\Services\NFeHistoryService::class, function ($c) {
            return new \CloudXM\NFe\Services\NFeHistoryService(
                $c->get(\CloudXM\NFe\Persistence\NfeHistoryRepository::class)
            );
        });

        // Register NFe Queue Service (depends on NfeQueueRepository)
        $this->container->singleton(\CloudXM\NFe\Services\NFeQueueService::class, function ($c) {
            return new \CloudXM\NFe\Services\NFeQueueService(
                $c->get(\CloudXM\NFe\Persistence\NfeQueueRepository::class)
            );
        });

        // Register NFeSchedulingService (Task 16.1)
        $this->container->singleton(\CloudXM\NFe\Services\NFeSchedulingService::class, function ($c) {
            return new \CloudXM\NFe\Services\NFeSchedulingService(
                $c->get(\CloudXM\NFe\Config\Configuration::class)
            );
        });

        // Register NFeWebhookProcessorService (Task 16.3)
        $this->container->singleton(\CloudXM\NFe\Services\NFeWebhookProcessorService::class, function ($c) {
            return new \CloudXM\NFe\Services\NFeWebhookProcessorService(
                $c->get(\CloudXM\NFe\Persistence\NfeEmissionsRepository::class),
                $c->get(\CloudXM\NFe\Services\NFeFileStorageService::class),
                $c->get(\CloudXM\NFe\Services\ApiClient::class),
                $c->get(\CloudXM\NFe\Services\NFeHistoryService::class),
                $c->get(\CloudXM\NFe\Config\Configuration::class)
            );
        });

        // Register NFe Automation Service (Task 16.4 — inject NFeSchedulingService)
        $this->container->singleton(\CloudXM\NFe\Services\NFeAutomationService::class, function ($c) {
            return new \CloudXM\NFe\Services\NFeAutomationService(
                $c->get(\CloudXM\NFe\Config\Configuration::class),
                $c->get(\CloudXM\NFe\Persistence\NfeEmissionsRepository::class),
                $c->get(\CloudXM\NFe\Services\ApiClient::class),
                $c->get(\CloudXM\NFe\Services\NFeFileStorageService::class),
                $c->get(\CloudXM\NFe\Services\OrderMapperV2::class),
                $c->get(\CloudXM\NFe\Services\NFeSchedulingService::class)
            );
        });

        // Register order invoice lifecycle service (UPDATED FOR V2)
        $this->container->singleton(\CloudXM\NFe\Services\OrderInvoiceLifecycleService::class, function ($c) {
            return new \CloudXM\NFe\Services\OrderInvoiceLifecycleService(
                $c->get(\CloudXM\NFe\Config\Configuration::class),
                $c->get(\CloudXM\NFe\Services\ApiClient::class),
                $c->get(\CloudXM\NFe\Services\OrderMapperV2::class),
                $c->get(\CloudXM\NFe\Persistence\NfeEmissionsRepository::class),
                $c->get(\CloudXM\NFe\Services\NFeHistoryService::class),
                $c->get(\CloudXM\NFe\Services\NFeFileStorageService::class)
            );
        });

        // Register NFe Queue Scheduler
        $this->container->singleton(\CloudXM\NFe\Services\NFeQueueScheduler::class);

        // Register NFe Queue Service
        $this->container->singleton(\CloudXM\NFe\Services\NFeQueueService::class, function ($c) {
            return new \CloudXM\NFe\Services\NFeQueueService(
                $c->get(\CloudXM\NFe\Persistence\NfeQueueRepository::class)
            );
        });

        // Register Admin Notice Controller
        $this->container->singleton(\CloudXM\NFe\Admin\Controllers\AdminNoticeController::class, function ($c) {
            return new \CloudXM\NFe\Admin\Controllers\AdminNoticeController(
                $c->get(\CloudXM\NFe\Services\NFeQueueService::class)
            );
        });
    }

    /**
     * Boot core services
     */
    public function boot(): void
    {
        add_action('woocommerce_order_status_changed', [$this, 'handleOrderStatusChanged'], 10, 3);

        add_action('updated_post_meta', [$this, 'handleOrderMetaUpdated'], 10, 4);
    }

    public function handleOrderStatusChanged(int $orderId, string $fromStatus, string $toStatus): void
    {
        $config = $this->container->get(\CloudXM\NFe\Config\Configuration::class);

        $autoIssueEnabled = $config->isAutoIssueEnabled();
        $autoIssueStatus = $config->getAutoIssueStatus();
        $autoCancelStatus = $config->getAutoCancelStatus();

        if ($autoIssueEnabled && $autoIssueStatus !== 'manual' && $toStatus === $autoIssueStatus) {
            $automation = $this->container->get(\CloudXM\NFe\Services\NFeAutomationService::class);
            $result = $automation->autoIssueNFe($orderId);
            $automation->setAutoStatus(
                $orderId,
                ($result['success'] ?? false) ? Configuration::AUTO_ISSUED : Configuration::AUTO_ERROR
            );
        }

        if ($autoCancelStatus !== 'disabled' && $toStatus === $autoCancelStatus) {
            $this->autoCancelNFe($orderId, $config);
        }
    }

    /**
     * Handle per-order meta flag updates.
     *
     * When _cloudxm_nfe_auto_status is set to 'ready_now' on an order,
     * automatically trigger the corresponding NFe action.
     */
    public function handleOrderMetaUpdated(int $metaId, int $objectId, string $metaKey, mixed $metaValue): void
    {
        if ($metaKey !== Configuration::META_AUTO_STATUS) {
            return;
        }

        // Only process when the new value is ready_now
        if ((string) $metaValue !== Configuration::AUTO_READY_NOW) {
            return;
        }

        $order = wc_get_order($objectId);
        if (!$order) {
            return;
        }

        // Skip if already issued
        $autoStatus = $order->get_meta(Configuration::META_AUTO_STATUS);
        if (in_array((string) $autoStatus, [Configuration::AUTO_ISSUED, Configuration::AUTO_SCHEDULE], true)) {
            return;
        }

        $this->container->get(\CloudXM\NFe\Services\NFeAutomationService::class)
            ->processOrderFlags($objectId);
    }

    private function autoCancelNFe(int $orderId, \CloudXM\NFe\Config\Configuration $config): void
    {
        $emissionRepo = $this->container->get(\CloudXM\NFe\Persistence\NfeEmissionsRepository::class);
        $emission = $emissionRepo->findByOrderId($orderId);

        if (!$emission || $emission['status'] === 'cancelled' || $emission['status'] === 'failed') {
            return;
        }

        $graceDays = $config->getCancelDaysLimit();
        $emissionDate = !empty($emission['emission_date']) ? new \DateTime($emission['emission_date']) : null;

        if ($emissionDate === null) {
            return;
        }

        $graceEnd = (clone $emissionDate)->modify("+{$graceDays} days");

        if (new \DateTime() <= $graceEnd) {
            try {
                $automationService = $this->container->get(\CloudXM\NFe\Services\NFeAutomationService::class);
                $automationService->cancelInvoice(
                    $emission['invoice_id'],
                    'Order automatically cancelled'
                );

                $emissionRepo->update($emission['id'], ['status' => 'cancelled']);

                $order = wc_get_order($orderId);
                if ($order) {
                    $order->update_meta_data('_cloudxm_nfe_status', 'cancelled');
                    $order->add_order_note(__('NFe cancelled automatically due to order status change.', 'cloudxm-nfe'));
                    $order->save();
                }
            } catch (\Throwable $e) {
                error_log('CloudXM NFe: Error cancelling NFe for order ' . $orderId . ': ' . $e->getMessage());
            }
        }
    }
}
