<?php

declare(strict_types=1);

namespace App\Console\Commands;

use App\Services\Sitemaps\SitemapBuildService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;

/**
 * Builds all sitemap documents and writes them as static .xml files to the
 * public disk (default: public/sitemaps/sitemap.xml and public/sitemaps/{name}.xml).
 *
 * Nginx can then serve those files directly (try_files $uri @php) without
 * hitting PHP at all. The SitemapController falls back to these same files
 * on the PHP path if a request does reach it before a static file exists.
 *
 * Run manually:   php artisan skinbase:sitemaps:generate
 * With filtering: php artisan skinbase:sitemaps:generate --only=artworks,users
 */
final class GenerateSitemapsCommand extends Command
{
    protected $signature = 'skinbase:sitemaps:generate
        {--only=* : Limit to specific sitemap families (comma or space separated)}
        {--disk=  : Override the target filesystem disk (default: sitemaps.static_publish.disk)}';

    protected $description = 'Build all sitemaps and write them as static .xml files to the configured public sitemap disk.';

    public function handle(SitemapBuildService $build): int
    {
        $totalStart = microtime(true);
        $families   = $this->selectedFamilies($build);

        if ($families === []) {
            $this->error('No valid sitemap families selected.');

            return self::INVALID;
        }

        $diskName = (string) ($this->option('disk') ?: config('sitemaps.static_publish.disk', 'sitemaps_public'));
        $disk     = Storage::disk($diskName);
        $written  = 0;
        $failed   = 0;

        $this->info('Disk: ' . $diskName);
        $this->info('Families: ' . implode(', ', $families));
        $this->newLine();

        // ── Root sitemap index ────────────────────────────────────────────
        $t = microtime(true);
        $index = $build->buildIndex(force: true, persist: false, families: $families);
        $disk->put('sitemaps/sitemap.xml', $index['content']);
        $written++;
        $this->line(sprintf(
            '  <info>✔</info>  sitemaps/sitemap.xml  %d entries  <comment>%.3fs</comment>',
            $index['url_count'],
            microtime(true) - $t,
        ));

        // ── Per-family documents ──────────────────────────────────────────
        foreach ($families as $family) {
            $familyStart = microtime(true);
            $names       = $build->canonicalDocumentNamesForFamily($family);

            $this->newLine();
            $this->line(sprintf('  <fg=cyan>%s</> (%d document(s))', $family, count($names)));

            foreach ($names as $documentName) {
                $t     = microtime(true);
                $built = $build->buildNamed($documentName, force: true, persist: false);

                if ($built === null) {
                    $this->line(sprintf('    <comment>–</comment>  %s  <fg=red>SKIPPED</>  (builder returned null)', $documentName));
                    $failed++;

                    continue;
                }

                $path = 'sitemaps/' . $documentName . '.xml';
                $disk->put($path, $built['content']);
                $written++;

                $this->line(sprintf(
                    '    <info>✔</info>  %s  %d URLs  <comment>%.3fs</comment>',
                    $documentName . '.xml',
                    $built['url_count'] ?? 0,
                    microtime(true) - $t,
                ));
            }

            $this->line(sprintf(
                '  <fg=cyan>%s</> done  <comment>%.3fs</comment>',
                $family,
                microtime(true) - $familyStart,
            ));
        }

        // ── Summary ───────────────────────────────────────────────────────
        $this->newLine();
        $this->info(sprintf(
            'Done: %d file(s) written, %d failed  total <comment>%.3fs</comment>',
            $written,
            $failed,
            microtime(true) - $totalStart,
        ));

        return $failed > 0 ? self::FAILURE : self::SUCCESS;
    }

    /** @return list<string> */
    private function selectedFamilies(SitemapBuildService $build): array
    {
        $only = [];

        foreach ((array) $this->option('only') as $value) {
            foreach (explode(',', (string) $value) as $family) {
                $normalized = trim($family);
                if ($normalized !== '') {
                    $only[] = $normalized;
                }
            }
        }

        $enabled = $build->enabledFamilies();

        if ($only === []) {
            return $enabled;
        }

        return array_values(array_filter($enabled, fn (string $f): bool => in_array($f, $only, true)));
    }
}
