<?php

declare(strict_types=1);

namespace Maestro\Core\Console\Commands;

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

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}
        {--refresh-cursor-rules : Overwrite .cursor/rules/*.mdc from package stubs}';

    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';

    /**
     * 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, HostIntegrityService $integrity): int
    {
        $force = (bool) $this->option('force');
        $republishConfig = (bool) $this->option('republish-config');
        $refreshCursorRules = (bool) $this->option('refresh-cursor-rules');

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

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

        if ($refreshCursorRules) {
            foreach ($publisher->publishCustomOverwrite(HostStubManifest::CURSOR_RULE_STUBS) as $path) {
                $this->info('Refreshed cursor rule: '.$path);
            }
        }

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

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

        $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->line('Audit host: php artisan maestro:host-integrity');
        $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)');

        $this->warnHostCoreForks($integrity);

        return self::SUCCESS;
    }

    private function warnHostCoreForks(HostIntegrityService $integrity): void
    {
        $forkCheck = null;
        foreach ($integrity->report()['checks'] as $check) {
            if ($check['id'] === 'core-view-forks') {
                $forkCheck = $check;
                break;
            }
        }

        if ($forkCheck === null || $forkCheck['status'] === 'ok') {
            return;
        }

        $this->newLine();
        $this->warn($forkCheck['detail']);
        $this->line('  See .cursor/rules/maestro-host-custom-code.mdc — Anti-patterns');
    }

    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 (is_array($repo) && ($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 mergeComposerAuditScript(): void
    {
        $path = base_path('composer.json');
        if (! File::exists($path)) {
            return;
        }

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

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

        if (isset($scripts['maestro-audit'])) {
            return;
        }

        $scripts['maestro-audit'] = [
            '@php artisan maestro:host-integrity --fail-on-warn',
            'bash scripts/check-no-maestro-link.sh',
        ];
        $data['scripts'] = $scripts;
        File::put($path, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
        $this->info('Added composer script maestro-audit');
    }

    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');
    }

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

        $contents = File::get($path);
        $original = $contents;

        $contents = preg_replace('/^\/\.cursor\/\s*$/m', '', $contents) ?? $contents;

        foreach (HostStubManifest::gitignoreEntries() as $entry) {
            if (preg_match('/^'.preg_quote($entry, '/').'\s*$/m', $contents)) {
                continue;
            }
            $contents = rtrim($contents).PHP_EOL.$entry.PHP_EOL;
        }

        if ($contents !== $original) {
            File::put($path, $contents);
            $this->info('Updated .gitignore for Maestro link state and cursor settings');
        }
    }
}
