<?php

namespace App\Console\Commands;

use App\Enums\ModerationContentType;
use App\Enums\ModerationStatus;
use App\Models\ContentModerationFinding;
use App\Services\Moderation\ContentModerationActionLogService;
use App\Services\Moderation\ContentModerationProcessingService;
use App\Services\Moderation\ContentModerationSourceService;
use Illuminate\Console\Command;

class RescanContentModerationCommand extends Command
{
    protected $signature = 'skinbase:rescan-content-moderation
        {--only= : comments, descriptions, titles, bios, profile-links, collections, stories, cards, or a comma-separated list}
        {--status=pending : Filter findings by moderation status}
        {--limit= : Maximum number of findings to rescan}
        {--from-id= : Start rescanning at or after this finding ID}
        {--force : Rescan all matching findings, including already resolved findings}';

    protected $description = 'Rescan existing moderation findings using the latest rules and scanner version.';

    public function __construct(
        private readonly ContentModerationProcessingService $processing,
        private readonly ContentModerationSourceService $sources,
        private readonly ContentModerationActionLogService $actionLogs,
    ) {
        parent::__construct();
    }

    public function handle(): int
    {
        $limit = max(0, (int) ($this->option('limit') ?? 0));
        $fromId = max(0, (int) ($this->option('from-id') ?? 0));
        $status = trim((string) ($this->option('status') ?? 'pending'));
        $force = (bool) $this->option('force');
        $types = $this->selectedTypes();

        $counts = [
            'rescanned' => 0,
            'updated' => 0,
            'auto_hidden' => 0,
            'missing_source' => 0,
        ];

        $query = ContentModerationFinding::query()->orderBy('id');

        if ($status !== '') {
            $query->where('status', $status);
        }

        if ($fromId > 0) {
            $query->where('id', '>=', $fromId);
        }

        if ($types !== []) {
            $query->whereIn('content_type', array_map(static fn (ModerationContentType $type): string => $type->value, $types));
        }

        if (! $force) {
            $query->where('status', ModerationStatus::Pending->value);
        }

        if ($limit > 0) {
            $query->limit($limit);
        }

        $query->chunkById(100, function ($findings) use (&$counts): bool {
            foreach ($findings as $finding) {
                $counts['rescanned']++;
                $rescanned = $this->processing->rescanFinding($finding, $this->sources);

                if ($rescanned === null) {
                    $counts['missing_source']++;
                    continue;
                }

                $counts['updated']++;
                if ($rescanned->is_auto_hidden) {
                    $counts['auto_hidden']++;
                }

                $this->actionLogs->log(
                    $rescanned,
                    'finding',
                    $rescanned->id,
                    'rescan',
                    null,
                    null,
                    $rescanned->status->value,
                    null,
                    null,
                    'Finding rescanned with the latest moderation rules.',
                    ['scanner_version' => $rescanned->scanner_version],
                );
            }

            return true;
        }, 'id');

        $this->table(['Metric', 'Count'], [
            ['Rescanned', $counts['rescanned']],
            ['Updated', $counts['updated']],
            ['Auto-hidden', $counts['auto_hidden']],
            ['Missing source', $counts['missing_source']],
        ]);

        $this->info('Content moderation rescan complete.');

        return self::SUCCESS;
    }

    /**
     * @return array<int, ModerationContentType>
     */
    private function selectedTypes(): array
    {
        $raw = trim((string) ($this->option('only') ?? ''));
        if ($raw === '') {
            return [];
        }

        $selected = \collect(explode(',', $raw))
            ->map(static fn (string $value): string => trim(strtolower($value)))
            ->filter()
            ->values();

        $types = [];

        if ($selected->contains('comments')) {
            $types[] = ModerationContentType::ArtworkComment;
        }

        if ($selected->contains('descriptions')) {
            $types[] = ModerationContentType::ArtworkDescription;
        }

        if ($selected->contains('titles') || $selected->contains('artwork_titles')) {
            $types[] = ModerationContentType::ArtworkTitle;
        }

        if ($selected->contains('bios') || $selected->contains('user_bios')) {
            $types[] = ModerationContentType::UserBio;
        }

        if ($selected->contains('profile-links') || $selected->contains('profile_links')) {
            $types[] = ModerationContentType::UserProfileLink;
        }

        if ($selected->contains('collections') || $selected->contains('collection_titles')) {
            $types[] = ModerationContentType::CollectionTitle;
            $types[] = ModerationContentType::CollectionDescription;
        }

        if ($selected->contains('stories') || $selected->contains('story_titles')) {
            $types[] = ModerationContentType::StoryTitle;
            $types[] = ModerationContentType::StoryContent;
        }

        if ($selected->contains('cards') || $selected->contains('card_titles')) {
            $types[] = ModerationContentType::CardTitle;
            $types[] = ModerationContentType::CardText;
        }

        return $types;
    }
}