<?php

declare(strict_types=1);

use App\Services\DberpAdminAccessService;
use App\Services\DberpNavigationPermissionDefinition;
use DBCore\Permission\Enums\PermissionEffect;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;

/**
 * 权限目录同步与历史角色授权补齐（合并原 grant_nav、grant_create_master_region、sync_data_import_permissions）。
 *
 * 空库安装时通常无角色数据，本迁移主要为 syncPermissionCatalog；有存量角色时按 legacy 规则写入 NAV_* 等授权。
 */
return new class extends Migration
{
    public function up(): void
    {
        app(DberpAdminAccessService::class)->syncPermissionCatalog();

        $this->grantCreateMasterRegionFromEdit();
        $this->grantNavPermissionsFromLegacy();
    }

    public function down(): void
    {
        $createId = DB::table('core_permissions')->where('name', 'create_master_region')->value('id');

        if ($createId !== null) {
            DB::table('core_role_permissions')->where('permission_id', (int) $createId)->delete();
            DB::table('core_permissions')->where('name', 'create_master_region')->delete();
        }

        $navCodes = array_keys(DberpNavigationPermissionDefinition::navCodeToLegacyPermissionCodes());
        $navIds = DB::table('core_permissions')->whereIn('name', $navCodes)->pluck('id')->map(fn (mixed $id): int => (int) $id)->all();

        if ($navIds !== []) {
            DB::table('core_role_permissions')->whereIn('permission_id', $navIds)->delete();
        }
    }

    private function grantCreateMasterRegionFromEdit(): void
    {
        $editId = DB::table('core_permissions')->where('name', 'edit_master_region')->value('id');
        $createId = DB::table('core_permissions')->where('name', 'create_master_region')->value('id');

        if ($editId === null || $createId === null) {
            return;
        }

        $editId = (int) $editId;
        $createId = (int) $createId;
        $now = now();

        foreach (DB::table('core_role_permissions')->where('permission_id', $editId)->get(['role_id', 'effect']) as $row) {
            DB::table('core_role_permissions')->updateOrInsert(
                [
                    'role_id' => (int) $row->role_id,
                    'permission_id' => $createId,
                ],
                [
                    'role_id' => (int) $row->role_id,
                    'permission_id' => $createId,
                    'effect' => (string) $row->effect,
                    'created_at' => $now,
                    'updated_at' => $now,
                ],
            );
        }
    }

    private function grantNavPermissionsFromLegacy(): void
    {
        foreach (DberpNavigationPermissionDefinition::navCodeToLegacyPermissionCodes() as $navCode => $legacyCodes) {
            $navId = DB::table('core_permissions')->where('name', $navCode)->value('id');
            if ($navId === null) {
                continue;
            }

            $navId = (int) $navId;
            $legacyIds = DB::table('core_permissions')->whereIn('name', $legacyCodes)->pluck('id')->map(fn (mixed $id): int => (int) $id)->all();

            if ($legacyIds === []) {
                continue;
            }

            $roleIds = DB::table('core_role_permissions')
                ->whereIn('permission_id', $legacyIds)
                ->distinct()
                ->pluck('role_id')
                ->map(fn (mixed $id): int => (int) $id)
                ->all();

            $now = now();

            foreach ($roleIds as $roleId) {
                DB::table('core_role_permissions')->updateOrInsert(
                    [
                        'role_id' => $roleId,
                        'permission_id' => $navId,
                    ],
                    [
                        'role_id' => $roleId,
                        'permission_id' => $navId,
                        'effect' => PermissionEffect::Allow->value,
                        'created_at' => $now,
                        'updated_at' => $now,
                    ],
                );
            }
        }
    }
};
