<?php

use App\Support\AdminPermissionBridge;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;

return new class extends Migration
{
    /** @var list<array{menu_code: string, action_code: string, permission_code: string, name: string}> */
    private const NEW_MENU_ACTIONS = [
        ['menu_code' => 'dashboard', 'action_code' => 'view', 'permission_code' => 'dashboard.view', 'name' => '仪表盘查看'],
        ['menu_code' => 'service.report', 'action_code' => 'export', 'permission_code' => 'service.report.export', 'name' => '报表导出'],
        ['menu_code' => 'risk.monitor', 'action_code' => 'manage', 'permission_code' => 'risk.monitor.manage', 'name' => '风控监控管理'],
    ];

    public function up(): void
    {
        $now = Carbon::now();
        $menuIds = DB::table('admin_menus')->pluck('id', 'code');
        $actionIds = DB::table('admin_action_catalog')->pluck('id', 'code');

        $menuActionIds = [];
        foreach (self::NEW_MENU_ACTIONS as $row) {
            $menuId = $menuIds[$row['menu_code']] ?? null;
            $actionId = $actionIds[$row['action_code']] ?? null;
            if ($menuId === null || $actionId === null) {
                continue;
            }

            $exists = DB::table('admin_menu_actions')
                ->where('permission_code', $row['permission_code'])
                ->exists();

            if ($exists) {
                $menuActionIds[$row['permission_code']] = (int) DB::table('admin_menu_actions')
                    ->where('permission_code', $row['permission_code'])
                    ->value('id');

                continue;
            }

            $menuActionIds[$row['permission_code']] = (int) DB::table('admin_menu_actions')->insertGetId([
                'menu_id' => (int) $menuId,
                'action_id' => (int) $actionId,
                'permission_code' => $row['permission_code'],
                'name' => $row['name'],
                'status' => 1,
                'created_at' => $now,
                'updated_at' => $now,
            ]);
        }

        $this->grantMenuActionsToAllRoles($menuActionIds, $now);
        $this->grantReportExportToReportViewRoles($menuActionIds['service.report.export'] ?? null, $now);
        $this->grantTicketsViewToLegacyRoles($menuActionIds, $now);
    }

    public function down(): void
    {
        $codes = array_column(self::NEW_MENU_ACTIONS, 'permission_code');
        $ids = DB::table('admin_menu_actions')->whereIn('permission_code', $codes)->pluck('id');
        foreach ($ids as $id) {
            DB::table('admin_role_menu_actions')->where('menu_action_id', (int) $id)->delete();
            DB::table('admin_user_menu_actions')->where('menu_action_id', (int) $id)->delete();
            DB::table('admin_api_resource_bindings')->where('menu_action_id', (int) $id)->delete();
            DB::table('admin_menu_actions')->where('id', (int) $id)->delete();
        }
    }

    /**
     * @param  array<string, int>  $menuActionIds
     */
    private function grantMenuActionsToAllRoles(array $menuActionIds, Carbon $now): void
    {
        $dashboardId = $menuActionIds['dashboard.view'] ?? null;
        if ($dashboardId === null) {
            return;
        }

        $roleIds = DB::table('admin_roles')->pluck('id');
        foreach ($roleIds as $roleId) {
            DB::table('admin_role_menu_actions')->updateOrInsert([
                'role_id' => (int) $roleId,
                'menu_action_id' => $dashboardId,
            ]);
        }
    }

    private function grantReportExportToReportViewRoles(?int $exportMenuActionId, Carbon $now): void
    {
        if ($exportMenuActionId === null) {
            return;
        }

        $viewMenuActionId = DB::table('admin_menu_actions')
            ->where('permission_code', 'service.report.view')
            ->value('id');

        if ($viewMenuActionId === null) {
            return;
        }

        $roleIds = DB::table('admin_role_menu_actions')
            ->where('menu_action_id', (int) $viewMenuActionId)
            ->distinct()
            ->pluck('role_id');

        foreach ($roleIds as $roleId) {
            DB::table('admin_role_menu_actions')->updateOrInsert([
                'role_id' => (int) $roleId,
                'menu_action_id' => $exportMenuActionId,
            ]);
        }
    }

    /**
     * 原注单入口依赖多种 prd.*；迁移为独立的 prd.tickets.view。
     *
     * @param  array<string, int>  $menuActionIds
     */
    private function grantTicketsViewToLegacyRoles(array $menuActionIds, Carbon $now): void
    {
        $ticketsViewId = DB::table('admin_menu_actions')
            ->where('permission_code', 'service.tickets.view')
            ->value('id');

        if ($ticketsViewId === null) {
            return;
        }

        $legacySlugs = [
            'prd.users.view_cs',
            'prd.users.manage',
            'prd.users.view_finance',
            'prd.draw_result.view',
            'prd.draw_result.manage',
            'prd.payout.view',
            'prd.payout.review',
            'prd.payout.manage',
        ];

        $roleIds = $this->roleIdsWithAnyLegacySlug($legacySlugs);

        foreach ($roleIds as $roleId) {
            DB::table('admin_role_menu_actions')->updateOrInsert([
                'role_id' => (int) $roleId,
                'menu_action_id' => (int) $ticketsViewId,
            ]);
        }

        $riskViewId = DB::table('admin_menu_actions')
            ->where('permission_code', 'risk.monitor.view')
            ->value('id');
        $riskManageId = $menuActionIds['risk.monitor.manage'] ?? null;

        if ($riskManageId === null) {
            return;
        }

        $riskRoleIds = $this->roleIdsWithAnyLegacySlug([
            'prd.draw_result.manage',
            'prd.draw_result.view',
            'prd.risk.manage',
            'prd.risk.view',
        ]);

        foreach ($riskRoleIds as $roleId) {
            if ($riskViewId !== null) {
                DB::table('admin_role_menu_actions')->updateOrInsert([
                    'role_id' => (int) $roleId,
                    'menu_action_id' => (int) $riskViewId,
                ]);
            }
            DB::table('admin_role_menu_actions')->updateOrInsert([
                'role_id' => (int) $roleId,
                'menu_action_id' => (int) $riskManageId,
            ]);
        }
    }

    /**
     * 通过角色已授权的 menu_action 反推曾拥有指定 prd.* 的角色（legacy 表已废弃）。
     *
     * @param  list<string>  $legacySlugs
     * @return list<int>
     */
    private function roleIdsWithAnyLegacySlug(array $legacySlugs): array
    {
        $codes = [];
        foreach ($legacySlugs as $slug) {
            $codes = array_merge($codes, AdminPermissionBridge::menuActionCodesForLegacy($slug));
        }
        $codes = array_values(array_unique($codes));

        if ($codes === []) {
            return [];
        }

        $menuActionIds = DB::table('admin_menu_actions')
            ->whereIn('permission_code', $codes)
            ->where('status', 1)
            ->pluck('id');

        if ($menuActionIds->isEmpty()) {
            return [];
        }

        return DB::table('admin_role_menu_actions')
            ->whereIn('menu_action_id', $menuActionIds->map(fn ($id) => (int) $id)->all())
            ->distinct()
            ->pluck('role_id')
            ->map(fn ($id) => (int) $id)
            ->all();
    }
};
