<?php

namespace Tests\Feature;

use App\Models\Permission;
use App\Models\Role;
use App\Models\User;
use App\Services\Authorization\AuthorizationAssignmentService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Schema;
use Tests\TestCase;

class AuthorizationLegacyBridgeRetirementTest extends TestCase
{
    use RefreshDatabase;

    public function test_legacy_authorization_pivots_are_absent_after_current_migrations(): void
    {
        $this->assertFalse(Schema::hasTable('role_user'));
        $this->assertFalse(Schema::hasTable('permission_role'));
        $this->assertTrue(Schema::hasTable('model_has_roles'));
        $this->assertTrue(Schema::hasTable('role_has_permissions'));
        $this->assertTrue(Schema::hasTable('model_has_permissions'));
        $this->assertSame(0, DB::table('model_has_permissions')->count());
    }

    public function test_canonical_assignment_service_operates_without_legacy_bridge_tables(): void
    {
        $user = User::factory()->create();
        $role = Role::query()->create([
            'name' => 'bridge-retirement-role',
            'guard_name' => 'web',
            'display_name' => 'Bridge Retirement Role',
            'description' => 'Regression role proving canonical assignments work after bridge retirement.',
            'is_system' => false,
        ]);
        $permission = Permission::query()->create([
            'name' => 'bridge-retirement.verify',
            'guard_name' => 'web',
            'display_name' => 'Verify bridge retirement',
            'group' => 'system',
            'description' => 'Regression permission for bridge retirement.',
        ]);

        $assignments = app(AuthorizationAssignmentService::class);
        $assignments->syncUserRoleIds($user, [$role->getKey()]);
        $assignments->syncRolePermissionIds($role, [$permission->getKey()]);

        $this->assertTrue(DB::table('model_has_roles')
            ->where('role_id', $role->getKey())
            ->where('model_type', User::class)
            ->where('model_id', $user->getKey())
            ->exists());
        $this->assertTrue(DB::table('role_has_permissions')
            ->where('permission_id', $permission->getKey())
            ->where('role_id', $role->getKey())
            ->exists());
        $this->assertTrue($user->fresh()->can('bridge-retirement.verify'));
        $this->assertFalse(Schema::hasTable('role_user'));
        $this->assertFalse(Schema::hasTable('permission_role'));
    }

    public function test_runtime_deployment_and_ci_source_cannot_reintroduce_legacy_bridge_dependencies(): void
    {
        $forbidden = [
            'role_user',
            'permission_role',
            'SpatiePermissionBridgeSynchronizer',
            'SpatiePermissionBridgeSeeder',
            'authorization:spatie-bridge',
            'authorization:bridge-retirement-readiness',
            'mirrorUserRoles(',
            'mirrorRolePermissions(',
            'syncLegacyFromSpatie(',
            '->hasPermission(',
        ];

        $paths = [
            app_path(),
            resource_path('views'),
            base_path('routes'),
            base_path('bootstrap'),
            base_path('config'),
            base_path('database/seeders'),
            base_path('deploy'),
            base_path('.github/workflows'),
            base_path('composer.json'),
        ];

        $violations = [];

        foreach ($paths as $path) {
            $files = File::isFile($path)
                ? [$path]
                : (File::isDirectory($path) ? collect(File::allFiles($path))->map->getPathname()->all() : []);

            foreach ($files as $file) {
                $contents = File::get($file);

                foreach ($forbidden as $needle) {
                    if (! str_contains($contents, $needle)) {
                        continue;
                    }

                    $relative = str_replace('\\', '/', $file);
                    $base = rtrim(str_replace('\\', '/', base_path()), '/').'/';
                    if (str_starts_with($relative, $base)) {
                        $relative = substr($relative, strlen($base));
                    }

                    $violations[] = $relative.' contains '.$needle;
                }
            }
        }

        $this->assertSame([], $violations, implode(PHP_EOL, $violations));
    }
}
