<?php

declare(strict_types=1);

namespace Maestro\Core\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
use Maestro\Core\Services\StubPublisher;

class CoreInstallCommand extends Command
{
    protected $signature = 'core:install
        {--force : Overwrite managed stub files even if already installed}
        {--republish-config : Overwrite published config/core.php and config/datatable.php}';

    protected $description = 'Publish Maestro CORE config, sync frontend stubs, and merge Composer / npm registry configuration';

    private const SATIS_URL = 'http://maestro-packages.build2connect.nl';

    private const VERDACCIO_SCOPE_REGISTRY = 'http://maestro-npm.build2connect.nl';

    /** @var array<string, string> stub path under stubs/ => path relative to project root */
    private const MANAGED_STUBS = [
        'vite.config.js' => 'vite.config.js',
        'tailwind.config.js' => 'tailwind.config.js',
        'routes/public.php' => 'routes/public.php',
        'routes/web.php' => 'routes/web.php',
        'app/Models/User.php' => 'app/Models/User.php',
        'database/seeders/DatabaseSeeder.php' => 'database/seeders/DatabaseSeeder.php',
        'resources/css/app.css' => 'resources/css/app.css',
        'resources/js/app.js' => 'resources/js/app.js',
        'resources/js/public-home.js' => 'resources/js/public-home.js',
        'resources/js/pages/Dashboard.vue' => 'resources/js/pages/Dashboard.vue',
        'resources/views/spa.blade.php' => 'resources/views/spa.blade.php',
    ];

    /** Published once; never overwritten by --force */
    private const CUSTOM_STUBS = [
        'database/seeders/CustomDatabaseSeeder.php' => 'database/seeders/CustomDatabaseSeeder.php',
        'app/Providers/CustomServiceProvider.php' => 'app/Providers/CustomServiceProvider.php',
        'config/custom.php' => 'config/custom.php',
        'resources/js/maestro/boot.js' => 'resources/js/maestro/boot.js',
        'resources/js/maestro/publicHome.vue' => 'resources/js/maestro/publicHome.vue',
        'resources/js/modules/custom/routes.js' => 'resources/js/modules/custom/routes.js',
        '.cursor/rules/maestro-host-custom-code.mdc' => '.cursor/rules/maestro-host-custom-code.mdc',
    ];

    /**
     * Vite config imports these from the app root; they are not always hoisted when @maestro/core is linked.
     *
     * @var array<string, string>
     */
    private const NPM_DEV_TOOLING = [
        '@primevue/auto-import-resolver' => '^4.3.1',
        '@vitejs/plugin-vue' => '^6.0.6',
        'sass-embedded' => '^1.93.3',
        'unplugin-vue-components' => '^0.27.5',
        'vue' => '^3.5.33',
    ];

    public function handle(StubPublisher $publisher): int
    {
        $force = (bool) $this->option('force');
        $republishConfig = (bool) $this->option('republish-config');

        $this->call('vendor:publish', [
            '--tag' => 'core-config',
            '--force' => $republishConfig,
        ]);

        foreach ($publisher->publishCustom(self::CUSTOM_STUBS) as $path) {
            $this->info('Published custom (host-owned): '.$path);
        }

        foreach ($publisher->publishManaged(self::MANAGED_STUBS, $force) as $path) {
            $this->info('Synced managed: '.$path);
        }

        $this->mergeComposerRepositories();
        $this->ensureComposerRequire();
        $this->mergePackageJsonDependencies();
        $this->mergeNpmDevTooling();
        $this->ensureNpmrc();

        $this->newLine();
        $this->info('Maestro CORE scaffolding updated.');
        $this->newLine();
        $this->line('Zones:');
        $this->line('  • Managed (@maestro-core-managed) — refreshed with --force');
        $this->line('  • Custom (app/Custom, resources/js/modules/custom, CustomDatabaseSeeder) — never overwritten');
        $this->newLine();
        $this->line('Register in AppServiceProvider: $this->app->register(\\App\\Providers\\CustomServiceProvider::class);');
        $this->line('New host feature: php artisan make:custom-feature {Name}');
        $this->line('See .cursor/rules/maestro-host-custom-code.mdc');
        $this->newLine();
        $this->line('Next steps:');
        $this->line('  1. php artisan migrate');
        $this->line('  2. php artisan db:seed');
        $this->line('  3. npm install');
        $this->line('  4. npm run build (or composer run dev)');

        return self::SUCCESS;
    }

    private function mergeComposerRepositories(): void
    {
        $path = base_path('composer.json');
        if (! File::exists($path)) {
            return;
        }

        $data = json_decode(File::get($path), true);
        if (! is_array($data)) {
            return;
        }

        $repos = $data['repositories'] ?? [];
        $repos = is_array($repos) ? $repos : [];

        $exists = false;
        foreach ($repos as $repo) {
            if (($repo['url'] ?? '') === self::SATIS_URL) {
                $exists = true;
                break;
            }
        }

        if (! $exists) {
            $repos[] = ['type' => 'composer', 'url' => self::SATIS_URL];
            $data['repositories'] = $repos;
            File::put($path, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
            $this->info('Added Satis repository to composer.json: '.self::SATIS_URL);
        }
    }

    private function ensureComposerRequire(): void
    {
        $path = base_path('composer.json');
        if (! File::exists($path)) {
            return;
        }

        $data = json_decode(File::get($path), true);
        if (! is_array($data)) {
            return;
        }

        $require = $data['require'] ?? [];
        $require = is_array($require) ? $require : [];

        if (! isset($require['maestro/core'])) {
            $require['maestro/core'] = '^1.0';
            $data['require'] = $require;
            File::put($path, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
            $this->warn('Added maestro/core to composer.json require — run: composer update maestro/core');
        }
    }

    private function mergePackageJsonDependencies(): void
    {
        $path = base_path('package.json');
        if (! File::exists($path)) {
            return;
        }

        $data = json_decode(File::get($path), true);
        if (! is_array($data)) {
            return;
        }

        $deps = $data['dependencies'] ?? [];
        $deps = is_array($deps) ? $deps : [];

        if (! isset($deps['@maestro/core'])) {
            $deps['@maestro/core'] = '^1.0.6';
            ksort($deps);
            $data['dependencies'] = $deps;
            File::put($path, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
            $this->warn('Added @maestro/core to package.json — run: npm install');
        }
    }

    private function mergeNpmDevTooling(): void
    {
        $path = base_path('package.json');
        if (! File::exists($path)) {
            return;
        }

        $data = json_decode(File::get($path), true);
        if (! is_array($data)) {
            return;
        }

        $dev = $data['devDependencies'] ?? [];
        $dev = is_array($dev) ? $dev : [];

        $changed = false;
        foreach (self::NPM_DEV_TOOLING as $pkg => $version) {
            if (! isset($dev[$pkg])) {
                $dev[$pkg] = $version;
                $changed = true;
            }
        }

        if ($changed) {
            ksort($dev);
            $data['devDependencies'] = $dev;
            File::put($path, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
            $this->warn('Added Maestro Vite/Vue devDependencies — run: npm install');
        }
    }

    private function ensureNpmrc(): void
    {
        $path = base_path('.npmrc');
        $line = '@maestro:registry='.self::VERDACCIO_SCOPE_REGISTRY.'/';

        if (File::exists($path)) {
            $contents = File::get($path);
            if (str_contains($contents, '@maestro:registry=')) {
                return;
            }
            File::append($path, PHP_EOL.$line.PHP_EOL);
            $this->info('Appended @maestro registry line to .npmrc');

            return;
        }

        File::put($path, $line.PHP_EOL);
        $this->info('Created .npmrc with Verdaccio scope for @maestro');
    }
}
