<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Intervention\Image\ImageManager;
use Mtc\ContentManager\Jobs\RegenerateSizesForMediaFileJob;
use Mtc\MercuryDataModels\Media as MediaModel;
use Mtc\MercuryDataModels\Tenant;

class ReimportMissingProviderImages extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'media:reimport-missing
                            {--tenant= : The tenant ID to process}
                            {--provider= : The image provider to check (e.g., auto-trader, car-and-driving)}
                            {--dry-run : Only report missing images without reimporting}
                            {--limit=0 : Limit the number of images to process (0 = no limit)}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Check for missing image files and reimport from source URL';

    private int $missingCount = 0;
    private int $reimportedCount = 0;
    private int $failedCount = 0;
    private int $processedCount = 0;

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

        if (!$tenant) {
            return self::FAILURE;
        }

        $this->info("Processing tenant: {$tenant->name} ({$tenant->id})");

        $provider = $this->option('provider') ?? $this->askForProvider();

        if (empty($provider)) {
            $this->error('No provider specified.');
            return self::FAILURE;
        }

        $isDryRun = $this->option('dry-run');
        $limit = (int) $this->option('limit');

        $this->info("Checking images from provider: {$provider}");
        if ($isDryRun) {
            $this->warn('DRY RUN MODE - No changes will be made');
        }

        $query = MediaModel::query()
            ->where('image_provider', $provider)
            ->whereNotNull('source_filename')
            ->where('source_filename', '!=', '');

        $totalCount = $query->count();
        $this->info("Found {$totalCount} images from provider '{$provider}' with source URLs");

        if ($totalCount === 0) {
            $this->info('No images to process.');
            return self::SUCCESS;
        }

        $progressBar = $this->output->createProgressBar($limit > 0 ? min($limit, $totalCount) : $totalCount);
        $progressBar->start();

        $query->chunkById(100, function (Collection $chunk) use ($isDryRun, $limit, $progressBar) {
            foreach ($chunk as $media) {
                if ($limit > 0 && $this->processedCount >= $limit) {
                    return false;
                }

                $this->checkAndReimport($media, $isDryRun);
                $this->processedCount++;
                $progressBar->advance();
            }

            return $limit === 0 || $this->processedCount < $limit;
        });

        $progressBar->finish();
        $this->newLine(2);

        $this->displaySummary($isDryRun);

        return self::SUCCESS;
    }

    private function initializeTenant(): ?Tenant
    {
        $tenantId = $this->option('tenant');

        if (empty($tenantId)) {
            $tenantId = $this->askForTenant();
        }

        if (empty($tenantId)) {
            $this->error('No tenant specified.');
            return null;
        }

        $tenant = Tenant::query()->find($tenantId);

        if (!$tenant) {
            $this->error("Tenant '{$tenantId}' not found.");
            return null;
        }

        tenancy()->initialize($tenant);

        return $tenant;
    }

    private function askForTenant(): ?string
    {
        $tenants = Tenant::query()
            ->whereNull('suspended_at')
            ->pluck('name', 'id')
            ->toArray();

        if (empty($tenants)) {
            $this->error('No active tenants found.');
            return null;
        }

        return $this->choice(
            'Select the tenant to process:',
            $tenants
        );
    }

    private function askForProvider(): ?string
    {
        $providers = MediaModel::query()
            ->whereNotNull('image_provider')
            ->distinct()
            ->pluck('image_provider')
            ->toArray();

        if (empty($providers)) {
            $this->error('No image providers found in the database.');
            return null;
        }

        return $this->choice(
            'Select the image provider to check:',
            $providers,
            0
        );
    }

    private function checkAndReimport(MediaModel $media, bool $isDryRun): void
    {
        $filePath = $media->path . '/' . $media->src;
        $disk = Config::get('filesystems.default_media');

        if (Storage::disk($disk)->exists($filePath)) {
            return;
        }

        $this->missingCount++;

        if ($isDryRun) {
            $this->newLine();
            $this->warn("Missing: ID={$media->id}, File={$filePath}");
            $this->line("  Source URL: {$media->source_filename}");
            return;
        }

        $this->attemptReimport($media);
    }

    private function attemptReimport(MediaModel $media): void
    {
        $sourceUrl = $media->source_filename;

        if (!filter_var($sourceUrl, FILTER_VALIDATE_URL)) {
            $this->newLine();
            $this->error("Invalid source URL for media ID={$media->id}: {$sourceUrl}");
            $this->failedCount++;
            return;
        }

        try {
            $disk = Config::get('filesystems.default_media');
            $filePath = $media->path . '/' . $media->src;
            $filePathJpg = str_replace('.webp', '.jpg', $filePath);

            // Download file contents from source URL
            $fileContents = @file_get_contents($sourceUrl);
            if ($fileContents === false) {
                throw new \Exception('Unable to download file from source URL');
            }

            // Process image through Intervention
            $image = (new ImageManager(Config::get('media.image_manager_config', [])))
                ->make($fileContents);

            // Store webp version
            Storage::disk($disk)->put(
                $filePath,
                $image->stream('webp'),
                ['visibility' => 'public']
            );

            // Store jpg version
            Storage::disk($disk)->put(
                $filePathJpg,
                $image->stream('jpg'),
                ['visibility' => 'public']
            );

            // Dispatch job to regenerate crop sizes
            RegenerateSizesForMediaFileJob::dispatch($media);

            $this->reimportedCount++;

            Log::info('Reimported missing image', [
                'media_id' => $media->id,
                'source_url' => $sourceUrl,
                'file_path' => $filePath,
            ]);
        } catch (\Exception $e) {
            $this->failedCount++;
            $this->newLine();
            $this->error("Failed to reimport media ID={$media->id}: {$e->getMessage()}");

            Log::warning('Failed to reimport missing image', [
                'media_id' => $media->id,
                'source_url' => $sourceUrl,
                'error' => $e->getMessage(),
            ]);
        }
    }

    private function displaySummary(bool $isDryRun): void
    {
        $this->info('=== Summary ===');
        $this->line("Total processed: {$this->processedCount}");
        $this->line("Missing files: {$this->missingCount}");

        if (!$isDryRun) {
            $this->line("Successfully reimported: {$this->reimportedCount}");
            $this->line("Failed to reimport: {$this->failedCount}");
        } else {
            $this->warn('Run without --dry-run to reimport missing images');
        }
    }
}
