<?php

declare(strict_types=1);

namespace App\Console\Commands;

use App\Filament\Resources\BackupSetResource;
use App\Models\BackupItem;
use App\Models\BackupSet;
use App\Models\Policy;
use App\Models\ManagedEnvironment;
use App\Models\ManagedEnvironmentMembership;
use App\Models\User;
use App\Models\UserTenantPreference;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Support\ManagedEnvironmentLinks;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Schema;

class SeedBackupHealthBrowserFixture extends Command
{
    protected $signature = 'tenantpilot:backup-health:seed-browser-fixture {--force-refresh : Rebuild the fixture backup basis even if it already exists}';

    protected $description = 'Seed a local/testing browser fixture for the Spec 180 blocked backup drill-through scenario.';

    public function handle(): int
    {
        if (! app()->environment(['local', 'testing'])) {
            $this->error('This fixture command is limited to local and testing environments.');

            return self::FAILURE;
        }

        $fixture = config('tenantpilot.backup_health.browser_smoke_fixture');

        if (! is_array($fixture)) {
            $this->error('The backup-health browser smoke fixture is not configured.');

            return self::FAILURE;
        }

        $workspaceConfig = is_array($fixture['workspace'] ?? null) ? $fixture['workspace'] : [];
        $userConfig = is_array($fixture['user'] ?? null) ? $fixture['user'] : [];
        $scenarioConfig = is_array($fixture['blocked_drillthrough'] ?? null) ? $fixture['blocked_drillthrough'] : [];
        $tenantRouteKey = (string) ($scenarioConfig['managed_environment_id'] ?? $scenarioConfig['tenant_external_id'] ?? '18000000-0000-4000-8000-000000000180');

        $workspace = Workspace::query()->updateOrCreate(
            ['slug' => (string) ($workspaceConfig['slug'] ?? 'spec-180-backup-health-smoke')],
            ['name' => (string) ($workspaceConfig['name'] ?? 'Spec 180 Backup Health Smoke')],
        );

        $password = (string) ($userConfig['password'] ?? 'password');

        $user = User::query()->updateOrCreate(
            ['email' => (string) ($userConfig['email'] ?? 'smoke-requester+180@tenantpilot.local')],
            [
                'name' => (string) ($userConfig['name'] ?? 'Spec 180 Requester'),
                'password' => Hash::make($password),
                'email_verified_at' => now(),
            ],
        );

        $tenant = ManagedEnvironment::query()->updateOrCreate(
            ['slug' => $tenantRouteKey],
            [
                'workspace_id' => (int) $workspace->getKey(),
                'name' => (string) ($scenarioConfig['tenant_name'] ?? 'Spec 180 Blocked Backup ManagedEnvironment'),
                'lifecycle_status' => ManagedEnvironment::STATUS_ACTIVE,
                'kind' => 'dev',
                'is_current' => false,
                'metadata' => ['fixture' => 'spec-180-browser-smoke'],
                'rbac_status' => 'ok',
                'rbac_last_checked_at' => now(),
            ],
        );

        WorkspaceMembership::query()->updateOrCreate(
            ['workspace_id' => (int) $workspace->getKey(), 'user_id' => (int) $user->getKey()],
            ['role' => 'owner'],
        );

        ManagedEnvironmentMembership::query()->updateOrCreate(
            ['managed_environment_id' => (int) $tenant->getKey(), 'user_id' => (int) $user->getKey()],
            ['role' => 'owner', 'source' => 'manual', 'source_ref' => 'spec-180-browser-smoke'],
        );

        if (Schema::hasColumn('users', 'last_workspace_id')) {
            $user->forceFill(['last_workspace_id' => (int) $workspace->getKey()])->save();
        }

        if (Schema::hasTable('user_managed_environment_preferences')) {
            UserTenantPreference::query()->updateOrCreate(
                ['user_id' => (int) $user->getKey(), 'managed_environment_id' => (int) $tenant->getKey()],
                ['last_used_at' => now()],
            );
        }

        $policy = Policy::query()->updateOrCreate(
            [
                'managed_environment_id' => (int) $tenant->getKey(),
                'external_id' => (string) ($scenarioConfig['policy_external_id'] ?? 'spec-180-rbac-stale-policy'),
                'policy_type' => (string) ($scenarioConfig['policy_type'] ?? 'settingsCatalogPolicy'),
            ],
            [
                'display_name' => (string) ($scenarioConfig['policy_name'] ?? 'Spec 180 RBAC Smoke Policy'),
                'platform' => 'windows',
                'last_synced_at' => now(),
                'metadata' => ['fixture' => 'spec-180-browser-smoke'],
            ],
        );

        $backupSet = BackupSet::withTrashed()->firstOrNew([
            'managed_environment_id' => (int) $tenant->getKey(),
            'name' => (string) ($scenarioConfig['backup_set_name'] ?? 'Spec 180 Blocked Stale Backup'),
        ]);

        $backupSet->forceFill([
            'created_by' => (string) $user->email,
            'status' => 'completed',
            'item_count' => 1,
            'completed_at' => now()->subHours(max(25, (int) ($scenarioConfig['stale_age_hours'] ?? 48))),
            'metadata' => ['fixture' => 'spec-180-browser-smoke'],
            'deleted_at' => null,
        ])->save();

        if (method_exists($backupSet, 'trashed') && $backupSet->trashed()) {
            $backupSet->restore();
        }

        $backupItem = BackupItem::withTrashed()->firstOrNew([
            'backup_set_id' => (int) $backupSet->getKey(),
            'policy_identifier' => (string) ($scenarioConfig['policy_external_id'] ?? 'spec-180-rbac-stale-policy'),
            'policy_type' => (string) ($scenarioConfig['policy_type'] ?? 'settingsCatalogPolicy'),
        ]);

        $backupItem->forceFill([
            'managed_environment_id' => (int) $tenant->getKey(),
            'policy_id' => (int) $policy->getKey(),
            'platform' => 'windows',
            'captured_at' => $backupSet->completed_at,
            'payload' => [
                'id' => (string) ($scenarioConfig['policy_external_id'] ?? 'spec-180-rbac-stale-policy'),
                'name' => (string) ($scenarioConfig['policy_name'] ?? 'Spec 180 RBAC Smoke Policy'),
            ],
            'metadata' => [
                'policy_name' => (string) ($scenarioConfig['policy_name'] ?? 'Spec 180 RBAC Smoke Policy'),
                'fixture' => 'spec-180-browser-smoke',
            ],
            'assignments' => [],
            'deleted_at' => null,
        ])->save();

        if (method_exists($backupItem, 'trashed') && $backupItem->trashed()) {
            $backupItem->restore();
        }

        if ((bool) $this->option('force-refresh')) {
            $backupSet->forceFill([
                'completed_at' => now()->subHours(max(25, (int) ($scenarioConfig['stale_age_hours'] ?? 48))),
            ])->save();

            $backupItem->forceFill([
                'captured_at' => $backupSet->completed_at,
            ])->save();
        }

        $this->table(
            ['Fixture', 'Value'],
            [
                ['Workspace', (string) $workspace->name],
                ['User email', (string) $user->email],
                ['User password', $password],
                ['ManagedEnvironment', (string) $tenant->name],
                ['ManagedEnvironment external id', (string) $tenant->external_id],
                ['Dashboard URL', ManagedEnvironmentLinks::viewUrl($tenant)],
                ['Fixture login URL', route('admin.local.backup-health-browser-fixture-login', absolute: false)],
                ['Blocked route', BackupSetResource::getUrl(panel: 'admin', tenant: $tenant)],
                ['Locally denied capability', 'tenant.view'],
            ],
        );

        $this->info('The dashboard remains visible for this fixture user, while backup drill-through routes stay forbidden via a local/testing-only capability deny seam.');

        return self::SUCCESS;
    }
}
