<?php

declare(strict_types=1);

namespace App\Console\Commands;

use App\Services\NNTP\NNTPService;
use App\Services\PostProcessService;
use Illuminate\Console\Command;

class UpdatePostProcess extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'update:postprocess
                            {type : Type (all, nfo, movies, tv, music, console, games, book, anime, additional, amazon)}
                            {echo? : Echo output (true/false, default: true)}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Post-process releases by type';

    /**
     * Valid types and whether they require NNTP.
     *
     * @var array<string, bool>
     */
    private const array VALID_TYPES = [
        'additional' => false,
        'all' => true,
        'amazon' => false,
        'anime' => false,
        'book' => false,
        'console' => false,
        'games' => false,
        'movies' => false,
        'music' => false,
        'nfo' => true,
        'tv' => false,
    ];

    public function __construct(
        private readonly PostProcessService $postProcessService
    ) {
        parent::__construct();
    }

    /**
     * Execute the console command.
     */
    public function handle(): int
    {
        $type = $this->argument('type');

        if (! array_key_exists($type, self::VALID_TYPES)) {
            $this->error("Invalid type: {$type}");
            $this->showHelp();

            return self::FAILURE;
        }

        try {
            $nntp = self::VALID_TYPES[$type] ? $this->getNntp() : null;

            match ($type) {
                'all' => $this->postProcessService->processAll($nntp ?? $this->getNntp()),
                'amazon' => $this->processAmazon(),
                'nfo' => $this->postProcessService->processNfos($nntp ?? $this->getNntp()),
                'movies' => $this->postProcessService->processMovies(),
                'music' => $this->postProcessService->processMusic(),
                'console' => $this->postProcessService->processConsoles(),
                'games' => $this->postProcessService->processGames(),
                'book' => $this->postProcessService->processBooks(),
                'anime' => $this->postProcessService->processAnime(),
                'tv' => $this->postProcessService->processTv(),
                'additional' => $this->postProcessService->processAdditional(),
            };

            return self::SUCCESS;
        } catch (\Throwable $e) {
            $this->error($e->getMessage());

            return self::FAILURE;
        }
    }

    /**
     * Show help text.
     */
    private function showHelp(): void
    {
        $this->line('');
        $this->line('Available types:');
        $this->line('  all         - Does all the types of post processing');
        $this->line('  nfo         - Processes NFO files');
        $this->line('  movies      - Processes movies');
        $this->line('  music       - Processes music');
        $this->line('  console     - Processes console games');
        $this->line('  games       - Processes games');
        $this->line('  book        - Processes books');
        $this->line('  anime       - Processes anime');
        $this->line('  tv          - Processes tv');
        $this->line('  additional  - Processes previews/mediainfo/etc...');
        $this->line('  amazon      - Processes books, music, console, and games');
    }

    /**
     * Process amazon types (books, music, console, games).
     */
    private function processAmazon(): void
    {
        $this->postProcessService->processBooks();
        $this->postProcessService->processMusic();
        $this->postProcessService->processConsoles();
        $this->postProcessService->processGames();
    }

    /**
     * Get NNTP connection.
     */
    private function getNntp(): NNTPService
    {
        $nntp = new NNTPService;

        $connectResult = config('nntmux_nntp.use_alternate_nntp_server') === true
            ? $nntp->doConnect(false, true)
            : $nntp->doConnect();

        if ($connectResult !== true) {
            $errorMessage = 'Unable to connect to usenet.';
            if (NNTPService::isError($connectResult)) {
                $errorMessage .= ' Error: '.$connectResult->getMessage();
            }
            throw new \RuntimeException($errorMessage);
        }

        return $nntp;
    }
}
