<?php

declare(strict_types=1);

namespace ViartasThemes\Protera\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Database\Seeder;
use ViartasCore\Themes\Models\Theme;
use ViartasCore\Themes\Services\ThemeManager;
use ViartasModules\Faq\Database\Seeders\FaqContentSeeder;
use ViartasModules\Menus\Database\Seeders\MenusSeeder;
use ViartasModules\News\Database\Seeders\NewsContentSeeder;
use ViartasModules\NewsCategories\Database\Seeders\NewsCategoriesContentSeeder;
use ViartasModules\Pages\Database\Seeders\PagesContentSeeder;
use ViartasThemes\Cleverphant\Console\Commands\ActivateCommand;
use ViartasThemes\Protera\Database\Seeders\ProteraContentWiper;

/**
 * php artisan protera:install [--additive] [--force] [--dry-run] [--skip-activate]
 *
 * The mirror of `cleverphant:install`: restores the tyre-domain (Protera) demo
 * content and makes Protera the default web theme again.
 *
 * DEFAULT — DESTRUCTIVE (task-34): removes every Cleverphant web content row
 * (Cleverphant-exclusive Pages + the `mokyklu-svetaines` blog + the
 * `bendrieji-klausimai` FAQ + orphaned menu items) BEFORE restoring the demo, so
 * /duk + /tinklarastis show ONLY the tyre content. The confirmation prompt
 * requires the operator to answer before the wipe runs unless --force /
 * --no-interaction is given. This inverts the pre-task-34 additive default.
 *
 * The tyre demo is NOT re-authored here — the command re-runs the existing demo
 * seeders (Pages / NewsCategories / News / Faq / Menus), exactly as
 * CmsBootSeeder does on a fresh install. They are idempotent (firstOrCreate), so
 * any row a wipe removed is recreated and any row that still exists is left as-is.
 *
 * Manual only — deliberately NOT wired into composer/deploy:sync.
 *
 *   --additive       KEEP the Cleverphant content (the old coexistence behaviour
 *                    prior to task-34). Both sets survive; Protera is (re)activated.
 *                    Skips the wipe. Risk #2: the shared kontaktai/pristatymas/
 *                    privatumo-politika pages are always kept either way.
 *   --force          Skip the destructive confirmation.
 *   --dry-run        Print the plan, touch nothing (skips wipe + seed + activate).
 *   --skip-activate  Restore content but leave the active theme unchanged.
 *
 * The wipe scope lives in {@see ProteraContentWiper}. The reverse (install
 * Cleverphant, activate it) is `cleverphant:install` (task-29/34).
 */
final class InstallCommand extends Command
{
    /**
     * @var string
     */
    protected $signature = 'protera:install
        {--additive : Keep pre-existing Cleverphant content; by default it is wiped before the restore}
        {--force : Skip the destructive confirmation}
        {--dry-run : Print the plan, do not touch the DB}
        {--skip-activate : Restore content but do not switch the active theme}';

    /**
     * @var string
     */
    protected $description = 'Restore the tyre (Protera) demo content and activate the Protera web theme';

    /**
     * The demo seeders to re-run, in dependency order (categories before their
     * children, Pages before Menus). Mirrors the CmsBootSeeder content order.
     *
     * @var list<class-string<Seeder>>
     */
    private const RESTORE_SEEDERS = [
        PagesContentSeeder::class,
        NewsCategoriesContentSeeder::class,
        NewsContentSeeder::class,
        FaqContentSeeder::class,
        MenusSeeder::class,
    ];

    /**
     * Run the full restore pipeline.
     */
    public function handle(): int
    {
        $additive = (bool) $this->option('additive');
        $force = (bool) $this->option('force');
        $dryRun = (bool) $this->option('dry-run');
        $skipActivate = (bool) $this->option('skip-activate');

        // task-34: the wipe is now the DEFAULT — --additive opts out of it and
        // restores the pre-task-34 coexistence behaviour.
        $fresh = ! $additive;

        // Destructive by default: confirm before wiping unless the operator opted
        // out of the wipe (--additive → $fresh is false), is only previewing
        // (--dry-run), has already confirmed via --force, or the shell is
        // non-interactive (--no-interaction). A declined confirmation aborts
        // cleanly with a success exit code — nothing was changed.
        if ($fresh && ! $dryRun && ! $force && ! (bool) $this->option('no-interaction')) {
            if (! $this->confirm('This will REMOVE existing Cleverphant web content and restore the tyre demo. Continue?', false)) {
                $this->warn('Aborted — no changes were made.');

                return self::SUCCESS;
            }
        }

        $this->info('Protera install '.($additive ? '(additive) ' : '(destructive) ').($dryRun ? '(dry-run) ' : '').'starting…');

        // Destructive default: clear the Cleverphant content BEFORE restoring the
        // demo so /duk + /tinklarastis end up tyre-only. --additive skips this;
        // dry-run just prints the plan. See ProteraContentWiper for scope.
        if ($fresh) {
            $this->components->task('Wipe Cleverphant content (ProteraContentWiper)', function () use ($dryRun): bool {
                $wiper = app(ProteraContentWiper::class);
                $wiper->setCommand($this);
                $wiper->dryRun($dryRun);
                $wiper->wipeCleverphantContent();

                return true;
            });
        }

        // Restore the tyre demo via the existing seeders (idempotent
        // firstOrCreate). Skipped entirely in dry-run — those seeders have no
        // dry-run mode, so a real run is the only way to invoke them.
        if ($dryRun) {
            foreach (self::RESTORE_SEEDERS as $seederClass) {
                $this->line("  - <fg=yellow>DRY</> would run {$seederClass}");
            }
        } else {
            foreach (self::RESTORE_SEEDERS as $seederClass) {
                $this->seedStep($seederClass);
            }
        }

        if (! $dryRun) {
            // Newly (re)seeded routes/permissions — keep the guest permissions in
            // sync so the public News route etc. are not 403 after a wipe. Idempotent.
            $this->components->task('cms:sync-permissions', function (): bool {
                $this->callSilent('cms:sync-permissions');

                return true;
            });
        }

        if (! $dryRun && ! $skipActivate) {
            $this->components->task('Activate Protera (default web theme)', function (): bool {
                $this->activateProtera();

                return true;
            });

            $this->components->task('optimize:clear', function (): bool {
                $this->callSilent('optimize:clear');

                return true;
            });
        }

        $this->newLine();

        if ($dryRun) {
            $this->info('Dry-run finished. No changes were made.');
        } elseif ($additive) {
            $this->info('Protera demo restored alongside existing rows'.($skipActivate ? '.' : ' and activated.'));
        } else {
            $this->info('Protera demo restored (Cleverphant content wiped)'.($skipActivate ? '.' : ' and activated.'));
        }

        return self::SUCCESS;
    }

    /**
     * Run one demo seeder as a console task.
     *
     * @param  class-string<Seeder>  $seederClass
     */
    private function seedStep(string $seederClass): void
    {
        $this->components->task($seederClass, function () use ($seederClass): bool {
            $seeder = app($seederClass);
            $seeder->setCommand($this);
            $seeder->run();

            return true;
        });
    }

    /**
     * Promote Protera to is_default=true (web env); demote every other web theme.
     *
     * Inline flip (mirrors {@see ActivateCommand})
     * so `protera:install` is self-contained and does not reach into the
     * Cleverphant theme package. Clears the theme resolution cache so the change
     * is visible on the next request.
     */
    private function activateProtera(): void
    {
        $protera = Theme::query()
            ->where('slug', 'protera')
            ->where('environment', 'web')
            ->first();

        if (! $protera) {
            $this->warn('Protera theme row not found in the web environment — activation skipped.');

            return;
        }

        // Demote every other web theme so exactly one stays default.
        Theme::query()
            ->where('environment', 'web')
            ->where('id', '!=', $protera->id)
            ->update(['is_default' => false]);

        $protera->update(['is_default' => true, 'is_active' => true]);

        app(ThemeManager::class)->clearCache();
    }
}
