<?php

namespace App\Console\Commands;

use App\Events\ModuleActivated;
use App\Models\Module;
use App\Models\Setting;
use App\Services\System\ModuleLoader;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Schema;

/**
 * module:install {directory}
 *
 * Registers a filesystem module into the modules DB table and activates it.
 * Use this during local development when you've placed a module directly in
 * the modules/ directory instead of uploading it via the admin UI.
 *
 * Usage:
 *   php artisan module:install Saas
 *   php artisan module:install Saas --no-activate
 *
 * After running this command, the module will be discovered by ModuleLoader::boot()
 * on the next request.
 */
class ModuleInstallCommand extends Command
{
    protected $signature = 'module:install
                            {directory : The module directory name (e.g. Saas, AiCvBuilder)}
                            {--no-activate : Register the module but leave it inactive}
                            {--reinstall : Clear setup flags and re-run the module setup seeder}';

    protected $description = 'Register a filesystem module into the DB and activate it';

    public function handle(): int
    {
        if (! Schema::hasTable('modules')) {
            $this->error('The modules table does not exist. Run php artisan migrate first.');
            return self::FAILURE;
        }

        $directory   = $this->argument('directory');
        $modulePath  = ModuleLoader::modulesPath($directory);
        $manifestPath = $modulePath . DIRECTORY_SEPARATOR . 'module.json';

        if (! File::isDirectory($modulePath)) {
            $this->error("Directory not found: modules/{$directory}");
            return self::FAILURE;
        }

        if (! File::exists($manifestPath)) {
            $this->error("module.json not found in modules/{$directory}");
            return self::FAILURE;
        }

        try {
            $module = ModuleLoader::install($modulePath);
        } catch (\RuntimeException $e) {
            $this->error('Install failed: ' . $e->getMessage());
            return self::FAILURE;
        }

        $this->info("Module [{$module->name}] registered (v{$module->version}).");

        if ($this->option('no-activate')) {
            $this->line("Skipped activation. Run `php artisan module:install {$directory}` without --no-activate to activate.");
            return self::SUCCESS;
        }

        // Run migrations
        $migrationPath = 'modules/' . $directory . '/database/migrations';
        if (! File::isDirectory(base_path($migrationPath))) {
            $migrationPath = 'modules/' . $directory . '/Database/Migrations';
        }

        if (File::isDirectory(base_path($migrationPath))) {
            $this->line("Running migrations from {$migrationPath}...");
            Artisan::call('migrate', ['--path' => $migrationPath, '--force' => true]);
            $this->line(trim(Artisan::output()) ?: 'Nothing to migrate.');
        }

        $module->activate();
        $this->info("Module [{$module->name}] activated.");

        // --reinstall: clear the setup_complete guard so the seeder runs again.
        // Mirrors AdminModulesController::reinstall(). Existing data is NOT deleted —
        // seeders use firstOrCreate, so only missing records are recreated.
        if ($this->option('reinstall')) {
            $settingKey = str_replace('-', '_', $module->slug) . '.setup_complete';
            Setting::where('key', $settingKey)->delete();
            Cache::forget('settings');
            $this->line("Setup flag cleared — seeder will run again.");
        }

        // Register the service provider now (it was inactive at process start so
        // ModuleLoader::boot() skipped it). Must happen before firing the event so
        // that the module's own event listeners (e.g. setup seeders) are wired up.
        if (! empty($module->provider_class) && class_exists($module->provider_class)) {
            app()->register($module->provider_class);
            $this->line("Service provider registered.");
        }

        // Fire ModuleActivated so setup seeders run and products are created.
        event(new ModuleActivated($module));
        $this->line("ModuleActivated event dispatched.");

        // Link public assets (e.g. public/modules/SeoAgents → modules/SeoAgents/public).
        ModuleLoader::linkAssets($directory);

        return self::SUCCESS;
    }
}
