<?php

declare(strict_types=1);

namespace Autogedal\AwbRetry\Console\Command;

use Autogedal\AwbRetry\Model\AwbErrorLogManager;
use Autogedal\AwbRetry\Model\Queue\RetryRequestPublisher;
use Eadesigndev\Awb\Model\AwbRepository;
use Eadesigndev\Awb\Model\Sources\CarrierType;
use Magento\Framework\App\Area;
use Magento\Framework\App\State;
use Magento\Framework\Console\Cli;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class SeedFailureCommand extends Command
{
    private const COMMAND_NAME = 'autogedal:awb-retry:seed-failure';
    private const OPTION_AWB_ID = 'awb-id';
    private const OPTION_MESSAGE = 'message';
    private const OPTION_MODE = 'mode';
    private const RETRY_MODE_MANUAL = RetryRequestPublisher::RETRY_MODE_MANUAL;
    private const RETRY_MODE_AUTOMATIC = RetryRequestPublisher::RETRY_MODE_AUTOMATIC;

    public function __construct(
        private readonly State $appState,
        private readonly AwbRepository $awbRepository,
        private readonly AwbErrorLogManager $errorLogManager,
        private readonly RetryRequestPublisher $retryRequestPublisher
    ) {
        parent::__construct();
    }

    protected function configure(): void
    {
        $this->setName(self::COMMAND_NAME)
            ->setDescription('Seed a synthetic AWB failure log and optionally queue it for retry')
            ->setDefinition([
                new InputOption(
                    self::OPTION_AWB_ID,
                    null,
                    InputOption::VALUE_REQUIRED,
                    'AWB entity ID to seed'
                ),
                new InputOption(
                    self::OPTION_MESSAGE,
                    null,
                    InputOption::VALUE_REQUIRED,
                    'Failure message to store in the retry log',
                    'Operation timed out after 30001 milliseconds with 0 bytes received'
                ),
                new InputOption(
                    self::OPTION_MODE,
                    null,
                    InputOption::VALUE_REQUIRED,
                    'Retry mode: automatic or manual',
                    self::RETRY_MODE_AUTOMATIC
                ),
            ]);
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $awbId = (int) $input->getOption(self::OPTION_AWB_ID);
        if ($awbId <= 0) {
            $output->writeln('<error>The --awb-id option is required.</error>');
            return Cli::RETURN_FAILURE;
        }

        $mode = strtolower(trim((string) $input->getOption(self::OPTION_MODE)));
        if (!in_array($mode, [self::RETRY_MODE_MANUAL, self::RETRY_MODE_AUTOMATIC], true)) {
            $output->writeln('<error>The --mode option must be manual or automatic.</error>');
            return Cli::RETURN_FAILURE;
        }

        $message = trim((string) $input->getOption(self::OPTION_MESSAGE));
        if ($message === '') {
            $message = 'Operation timed out after 30001 milliseconds with 0 bytes received';
        }

        try {
            $this->appState->emulateAreaCode(
                Area::AREA_FRONTEND,
                function () use ($awbId, $message, $mode, $output): void {
                    $awb = $this->awbRepository->getById($awbId);
                    $carrierId = (int) $awb->getData('carrier_id');
                    $carrierCode = $this->resolveCarrierCode($carrierId);
                    $log = $this->errorLogManager->upsertFailure(
                        $awbId,
                        $carrierId,
                        $carrierCode,
                        new \RuntimeException($message),
                        1,
                        [
                            'source' => 'console',
                            'command' => self::COMMAND_NAME,
                            'retry_mode' => $mode,
                        ]
                    );

                    $output->writeln('<info>Seeded AWB failure log #' . (int) $log->getId() . ' for AWB ' . $awbId . '.</info>');

                    if ($mode === self::RETRY_MODE_AUTOMATIC) {
                        $this->retryRequestPublisher->queue(
                            (int) $log->getId(),
                            RetryRequestPublisher::RETRY_MODE_AUTOMATIC
                        );
                        $output->writeln('<info>Queued automatic retry for log #' . (int) $log->getId() . '.</info>');
                    }
                }
            );
        } catch (\Throwable $e) {
            $output->writeln('<error>' . $e->getMessage() . '</error>');
            return Cli::RETURN_FAILURE;
        }

        return Cli::RETURN_SUCCESS;
    }

    private function resolveCarrierCode(int $carrierId): string
    {
        return match ($carrierId) {
            CarrierType::PACKETA_SAMEDAY,
            CarrierType::PACKETA_FAN_COURIER => 'packeta',
            default => CarrierType::$carriersSettingsPath[$carrierId] ?? '',
        };
    }
}
