<?php

use App\Models\Organization;
use App\Models\Permission;
use App\Models\Role;
use App\Models\User;
use App\Support\Authorization\PermissionCatalog;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Spatie\Permission\PermissionRegistrar;

return new class extends Migration
{
    public function up(): void
    {
        app(PermissionRegistrar::class)->forgetCachedPermissions();

        foreach (PermissionCatalog::allPermissionNames() as $permissionName) {
            Permission::findOrCreate($permissionName, 'web');
        }

        $adminRole = Role::query()->firstOrCreate(
            ['code' => User::ROLE_ADMIN, 'guard_name' => 'web'],
            [
                'name' => User::ROLE_ADMIN,
                'organization_id' => null,
                'is_system' => true,
                'is_active' => true,
            ]
        );
        $adminRole->syncPermissions(PermissionCatalog::permissionNamesForPanel(PermissionCatalog::PANEL_ADMIN));

        foreach (Organization::query()->get(['id']) as $organization) {
            $ownerRole = Role::query()->firstOrCreate(
                [
                    'code' => PermissionCatalog::ownerSystemRoleCode((int) $organization->id),
                    'guard_name' => 'web',
                ],
                [
                    'name' => 'OWNER',
                    'organization_id' => (int) $organization->id,
                    'is_system' => true,
                    'is_active' => true,
                ]
            );

            $ownerRole->syncPermissions(PermissionCatalog::permissionNamesForPanel(PermissionCatalog::PANEL_OWNER));
        }

        if (Schema::hasTable('staff_roles')) {
            $legacyRoles = DB::table('staff_roles')
                ->select(['name', 'code', 'organization_id', 'permissions', 'is_system', 'is_active'])
                ->get();

            foreach ($legacyRoles as $legacyRole) {
                $role = Role::query()->firstOrCreate(
                    ['code' => $legacyRole->code, 'guard_name' => 'web'],
                    [
                        'name' => $legacyRole->name,
                        'organization_id' => $legacyRole->organization_id,
                        'is_system' => (bool) $legacyRole->is_system,
                        'is_active' => (bool) $legacyRole->is_active,
                    ]
                );

                $role->fill([
                    'name' => $legacyRole->name,
                    'organization_id' => $legacyRole->organization_id,
                    'is_system' => (bool) $legacyRole->is_system,
                    'is_active' => (bool) $legacyRole->is_active,
                ])->save();

                $legacyPermissions = json_decode((string) ($legacyRole->permissions ?? '[]'), true);
                $panel = empty($legacyRole->organization_id)
                    ? PermissionCatalog::PANEL_ADMIN
                    : PermissionCatalog::PANEL_OWNER;

                $role->syncPermissions(
                    PermissionCatalog::mapLegacyPermissions(
                        is_array($legacyPermissions) ? $legacyPermissions : [],
                        $panel
                    )
                );
            }
        }

        $adminUsers = User::query()->where('role', User::ROLE_ADMIN)->get();
        foreach ($adminUsers as $user) {
            setPermissionsTeamId(PermissionCatalog::GLOBAL_TEAM_ID);
            $user->syncRoles([$adminRole]);
        }

        $platformStaffUsers = User::query()->where('role', User::ROLE_STAFF)->get();
        foreach ($platformStaffUsers as $user) {
            setPermissionsTeamId(PermissionCatalog::GLOBAL_TEAM_ID);

            if (!empty($user->staff_role)) {
                $role = Role::query()
                    ->where('code', $user->staff_role)
                    ->whereNull('organization_id')
                    ->first();

                if ($role) {
                    $user->syncRoles([$role]);
                }
            }
        }

        $ownerUsers = User::query()
            ->where('role', User::ROLE_CLIENT)
            ->whereNotNull('organization_id')
            ->get();

        foreach ($ownerUsers as $user) {
            $organizationId = (int) ($user->organization_id ?? 0);
            if ($organizationId <= 0) {
                continue;
            }

            $ownerRole = Role::query()
                ->where('code', PermissionCatalog::ownerSystemRoleCode($organizationId))
                ->where('organization_id', $organizationId)
                ->first();

            if (!$ownerRole) {
                continue;
            }

            setPermissionsTeamId($organizationId);
            $user->syncRoles([$ownerRole]);
        }

        $ownerStaffUsers = User::query()
            ->where('role', User::ROLE_OWNER_STAFF)
            ->whereNotNull('organization_id')
            ->get();

        foreach ($ownerStaffUsers as $user) {
            $organizationId = (int) ($user->organization_id ?? 0);
            if ($organizationId <= 0 || empty($user->staff_role)) {
                continue;
            }

            $role = Role::query()
                ->where('code', $user->staff_role)
                ->where('organization_id', $organizationId)
                ->first();

            if (!$role) {
                continue;
            }

            setPermissionsTeamId($organizationId);
            $user->syncRoles([$role]);
        }

        app(PermissionRegistrar::class)->forgetCachedPermissions();
    }

    public function down(): void
    {
        $roleCodes = collect([User::ROLE_ADMIN])
            ->merge(
                Organization::query()
                    ->pluck('id')
                    ->map(fn ($id) => PermissionCatalog::ownerSystemRoleCode((int) $id))
            )
            ->values()
            ->all();

        $roleIds = Role::query()->whereIn('code', $roleCodes)->pluck('id');

        DB::table('role_has_permissions')->whereIn('role_id', $roleIds)->delete();
        DB::table('model_has_roles')->whereIn('role_id', $roleIds)->delete();
        DB::table('permissions')->whereIn('name', PermissionCatalog::allPermissionNames())->delete();
        DB::table('roles')->whereIn('id', $roleIds)->delete();
    }
};
