<?php

namespace Modules\SaasSwitcher\Console;

use App\Business;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Spatie\Permission\Models\Permission;

/**
 * Seeds per-business module entitlements into each SaaS project DB, and (unless
 * --skip-permissions) ensures the project's vertical permissions exist and are
 * assigned to the default roles so NON-admin users work too.
 *
 * Runs per-connection (config saasswitcher.projects). Permissions are CREATED
 * directly (Permission::findOrCreate) rather than via `migrate`, because the
 * forked project DBs record the permission migrations as already-run while the
 * rows are actually absent — so `migrate` would skip them.
 *
 *   php artisan entitlements:seed --dry-run
 *   php artisan entitlements:seed
 *   php artisan entitlements:seed --project=shifa --project=vet
 *   php artisan entitlements:seed --skip-permissions
 */
class SeedModuleEntitlements extends Command
{
    protected $signature = 'entitlements:seed
        {--project=* : Limit to these SaaS project keys (default: all)}
        {--skip-permissions : Only set entitlements; do not create/assign vertical permissions}
        {--dry-run : Show what would change without writing}';

    protected $description = 'Seed per-business module entitlements (+ vertical perms/roles) into each SaaS project DB';

    /** vertical key => DefaultRolesSeeder class that owns its perms/roles. */
    protected array $verticalSeeders = [
        'clinic' => \Modules\ClinicCore\Services\DefaultRolesSeeder::class,
        'vet'    => \Modules\VetClinic\Services\DefaultRolesSeeder::class,
    ];

    public function handle(): int
    {
        $projects = config('saasswitcher.projects', []);
        $only     = $this->option('project');
        $dry      = (bool) $this->option('dry-run');
        $skipPerm = (bool) $this->option('skip-permissions');
        $original = DB::getDefaultConnection();

        if (empty($projects)) {
            $this->error('No projects configured (config saasswitcher.projects). Is SaasSwitcher enabled?');
            return self::FAILURE;
        }

        foreach ($projects as $key => $proj) {
            if (! empty($only) && ! in_array($key, $only, true)) {
                continue;
            }
            $conn = $proj['connection'] ?? null;
            if (! $conn) {
                continue;
            }

            $modules   = config("saasswitcher.project_modules.$key", null); // null = fail-open (all)
            $verticals = (array) config("saasswitcher.project_verticals.$key", []);

            $entDesc = $modules === null
                ? 'NULL (fail-open / all modules)'
                : (empty($modules) ? '[] (none — clean base ERP)' : implode(', ', $modules));
            $this->info("== Project '{$key}' (connection {$conn}) ==");
            $this->line('   entitlements => '.$entDesc);

            DB::setDefaultConnection($conn);
            $this->forgetPermCache();

            try {
                $businesses = Business::query()->get(['id', 'name']);
                if ($businesses->isEmpty()) {
                    $this->warn('   (no businesses in this DB)');
                    continue;
                }

                foreach ($businesses as $b) {
                    // (a) Entitlements — write raw JSON (no model cast needed).
                    if ($dry) {
                        $this->line("   [dry] business {$b->id} ({$b->name}) entitlements -> ".($modules === null ? 'NULL' : json_encode($modules)));
                    } else {
                        Business::on($conn)->where('id', $b->id)->update([
                            'module_entitlements' => $modules === null ? null : json_encode(array_values($modules)),
                        ]);
                        $this->line("   business {$b->id} ({$b->name}) entitlements set");
                    }

                    // (b) Make the per-user permission axis real for non-admins.
                    if (! $skipPerm && ! $dry) {
                        foreach ($verticals as $v) {
                            $this->seedVertical($v, (int) $b->id);
                        }
                    }
                }
            } catch (\Throwable $e) {
                $this->error("   FAILED on {$conn}: ".$e->getMessage());
            } finally {
                DB::setDefaultConnection($original);
                $this->forgetPermCache();
            }
        }

        $this->info($dry ? 'Dry run complete (no changes written).' : 'Done.');

        return self::SUCCESS;
    }

    /** Ensure a vertical's permissions exist and its default roles are assigned them. Idempotent. */
    protected function seedVertical(string $vertical, int $businessId): void
    {
        $seeder = $this->verticalSeeders[$vertical] ?? null;
        if (! $seeder || ! class_exists($seeder) || ! defined("$seeder::PRESETS")) {
            return;
        }

        $perms = collect($seeder::PRESETS)->flatten()->unique()->values();
        foreach ($perms as $p) {
            Permission::findOrCreate($p, 'web');
        }

        $created = method_exists($seeder, 'seedForBusiness') ? $seeder::seedForBusiness($businessId) : 0;
        $this->line("      [{$vertical}] ensured {$perms->count()} perms; default roles seeded (created {$created})");
    }

    protected function forgetPermCache(): void
    {
        try {
            app(\Spatie\Permission\PermissionRegistrar::class)->forgetCachedPermissions();
        } catch (\Throwable $e) {
            // ignore
        }
    }
}
