<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Routing\Router;
use Illuminate\Support\Collection;
use Spatie\Permission\Models\Permission;

class AuditPermissions extends Command
{
    protected $signature = 'permissions:audit
                            {--fix : Create missing permissions in the database}
                            {--json : Output results as JSON}';

    protected $description = 'Compare route middleware permissions against the database and report gaps';

    public function __construct(private Router $router)
    {
        parent::__construct();
    }

    public function handle(): int
    {
        $routePerms = $this->collectRoutePermissions();
        $dbPerms = Permission::pluck('name')->map(fn ($n) => strtolower($n))->toArray();

        $missing = $routePerms->filter(fn ($p) => ! in_array(strtolower($p), $dbPerms))->values();
        $orphaned = collect($dbPerms)->filter(fn ($p) => ! $routePerms->map(fn ($r) => strtolower($r))->contains($p))->values();

        if ($this->option('json')) {
            $this->line(json_encode(compact('missing', 'orphaned'), JSON_PRETTY_PRINT));

            return self::SUCCESS;
        }

        $this->info('=== Permission Audit ===');
        $this->newLine();

        if ($missing->isEmpty()) {
            $this->line('<fg=green>✓ All route permissions exist in database.</>');
        } else {
            $this->warn("Missing in database ({$missing->count()} permissions used in routes but not in DB):");
            $missing->each(fn ($p) => $this->line("  - {$p}"));

            if ($this->option('fix')) {
                $missing->each(fn ($p) => Permission::findOrCreate($p, 'web'));
                $this->info("Created {$missing->count()} missing permission(s).");
            }
        }

        $this->newLine();

        if ($orphaned->isEmpty()) {
            $this->line('<fg=green>✓ No orphaned permissions in database.</>');
        } else {
            $this->warn("Orphaned in database ({$orphaned->count()} permissions in DB but not used in any route):");
            $orphaned->each(fn ($p) => $this->line("  - {$p}"));
        }

        return $missing->isEmpty() ? self::SUCCESS : self::FAILURE;
    }

    private function collectRoutePermissions(): Collection
    {
        $permissions = collect();

        foreach ($this->router->getRoutes() as $route) {
            $middleware = $route->gatherMiddleware();

            foreach ($middleware as $mw) {
                if (is_string($mw) && str_starts_with($mw, 'permission:')) {
                    $perm = trim(str_replace('permission:', '', $mw));
                    $permissions->push($perm);
                }
            }
        }

        return $permissions->unique()->sort()->values();
    }
}
