<?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 InjectTransientFailureCommand extends Command
{
    private const COMMAND_NAME = 'autogedal:awb-retry:inject-transient-failure';
    private const OPTION_AWB_ID = 'awb-id';
    private const OPTION_MESSAGE = 'message';

    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 and queue a synthetic transient AWB failure for consumer-loop testing')
            ->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,
                    'Transient failure message to simulate',
                    'Operation timed out after 30001 milliseconds with 0 bytes received'
                ),
            ]);
    }

    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;
        }

        $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, $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,
                            'simulate_failure' => true,
                            'simulate_message' => $message,
                        ]
                    );

                    $this->retryRequestPublisher->queue(
                        (int) $log->getId(),
                        RetryRequestPublisher::RETRY_MODE_AUTOMATIC,
                        [
                            'simulate_failure' => true,
                            'simulate_message' => $message,
                        ]
                    );

                    $output->writeln('<info>Seeded and queued synthetic transient failure 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] ?? '',
        };
    }
}
