<?php
declare(strict_types=1);

namespace FiloBlu\Refilo\Console\Command;

use Magento\Framework\App\ResourceConnection;
use Magento\Framework\Console\Cli;
use Magento\Framework\Indexer\IndexerRegistry;
use Magento\Framework\Mview\ViewInterfaceFactory;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Command to reset the changelog table for a specified Magento 2 indexer.
 *
 * This command performs the following actions:
 * - Truncates the changelog table associated with the provided indexer ID.
 * - Resets the mview state version to 1 for the indexer.
 * - Optionally invalidates the indexer if the `--invalidate` option is set.
 *
 * Usage:
 *   bin/magento refilo:reset:changelog <indexer_id> [--invalidate]
 *
 * Arguments:
 *   indexer_id   The ID of the indexer (e.g. catalog_product_price)
 *
 * Options:
 *   --invalidate   If set, the indexer will be invalidated after truncating the changelog.
 *
 * Dependencies:
 * - ResourceConnection: Provides access to the database.
 * - ViewInterfaceFactory: Used to load the mview view for the indexer.
 * - IndexerRegistry: Retrieves and invalidates indexers.
 */
class ResetChangeLogForIndex extends Command
{
    const ARG_INDEXER_ID = 'indexer_id';
    const ARG_INVALIDATE = 'invalidate';

    /**
     * @var ResourceConnection
     */
    private $resourceConnection;
    /**
     * @var ViewInterfaceFactory
     */
    private $viewFactory;
    /**
     * @var IndexerRegistry
     */
    private $indexerRegistry;

    /**
     * @param ResourceConnection $resourceConnection
     * @param ViewInterfaceFactory $viewFactory
     * @param IndexerRegistry $indexerRegistry
     */
    public function __construct(
        ResourceConnection   $resourceConnection,
        ViewInterfaceFactory $viewFactory,
        IndexerRegistry      $indexerRegistry
    )
    {
        $this->resourceConnection = $resourceConnection;
        $this->viewFactory = $viewFactory;
        $this->indexerRegistry = $indexerRegistry;
        parent::__construct();
    }

    /**
     * Configures the command definition.
     *
     * Sets the command name, description, required arguments, and available options.
     * - Argument: indexer_id (required) - The ID of the indexer (e.g. catalog_product_price).
     * - Option: --invalidate - If set, the indexer will be invalidated after truncating the changelog.
     *
     * @return void
     */
    protected function configure()
    {
        $this->setName('refilo:changelog:reset')
            ->setDescription('Truncate changelog table and optionally invalidate indexer')
            ->addArgument(self::ARG_INDEXER_ID, InputArgument::REQUIRED, 'Indexer ID (e.g. catalog_product_price)')
            ->addOption('invalidate', 'i', InputOption::VALUE_NONE, 'Invalidate the indexer after truncating the changelog');
    }

    /**
     * Executes the command to truncate the changelog table for the specified indexer,
     * resets the mview state version to 1, and optionally invalidates the indexer.
     *
     * @param InputInterface $input
     * @param OutputInterface $output
     * @return int
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $indexerId = $input->getArgument(self::ARG_INDEXER_ID);
        $invalidate = $input->getOption('invalidate');

        try {
            $connection = $this->resourceConnection->getConnection();

            $view = $this->viewFactory->create();
            $view->load($indexerId);

            $clTable = $view->getChangelog()->getName();

            $output->writeln("<info>Truncating changelog table: {$clTable}</info>");
            $connection->truncateTable($clTable);
            $connection->query("ALTER TABLE `{$clTable}` AUTO_INCREMENT = 1");
            $connection->query('ANALYZE TABLE ' . $clTable);

            $state = $view->getState();
            $state->setVersionId(0);
            $state->save();

            $output->writeln("<info>mview_state updated: version_id set to 0</info>");

            if ($invalidate) {
                $indexer = $this->indexerRegistry->get($indexerId);
                $indexer->invalidate();
                $output->writeln("<comment>Indexer '{$indexerId}' invalidated.</comment>");
            }

            return Cli::RETURN_SUCCESS;

        } catch (\Exception $e) {
            $output->writeln("<error>Error: {$e->getMessage()}</error>");
            return Cli::RETURN_FAILURE;
        }
    }

}
