<?php

namespace App\Services;

use App\Models\Commons\Menu;
use App\Models\Permission;
use App\Models\Scopes\TenantScope;
use App\Models\User;
use Illuminate\Support\Facades\DB;

class UserPermissionService
{
    /**
     * 권한 유형 목록
     */
    private array $permissionTypes = ['view', 'create', 'update', 'delete', 'approve', 'export', 'manage'];

    /**
     * 사용자의 권한 매트릭스 조회 (역할 + 부서 + 개인 오버라이드 통합)
     * 각 권한에 대해 최종 상태와 소스 정보 반환
     *
     * @param  int  $userId  사용자 ID
     * @param  int|null  $tenantId  테넌트 ID
     * @param  string  $guardName  Guard 이름 (api 또는 web)
     * @return array 메뉴별 권한 상태 매트릭스
     *               [menuId][type] = ['effective' => 'allow'|'deny'|null, 'source' => 'role'|'department'|'personal'|null, 'personal' => 'allow'|'deny'|null]
     */
    public function getUserPermissionMatrix(int $userId, ?int $tenantId = null, string $guardName = 'api'): array
    {
        $now = now();

        // 1. 역할 권한 조회 (Spatie + user_roles)
        $rolePermissions = $this->getRolePermissions($userId, $guardName, $tenantId);

        // 2. 부서 권한 조회 (permission_overrides with Department)
        $departmentPermissions = $this->getDepartmentPermissions($userId, $tenantId, $guardName);

        // 3. 개인 오버라이드 조회 (permission_overrides with User)
        $personalOverrides = $this->getPersonalOverrides($userId, $tenantId, $guardName);

        // 4. 통합 매트릭스 생성
        $permissions = [];

        // 모든 메뉴 ID 수집
        $allMenuIds = array_unique(array_merge(
            array_keys($rolePermissions),
            array_keys($departmentPermissions),
            array_keys($personalOverrides)
        ));

        foreach ($allMenuIds as $menuId) {
            if (! isset($permissions[$menuId])) {
                $permissions[$menuId] = [];
            }

            foreach ($this->permissionTypes as $type) {
                $hasRole = isset($rolePermissions[$menuId][$type]) && $rolePermissions[$menuId][$type];
                $hasDept = isset($departmentPermissions[$menuId][$type]) && $departmentPermissions[$menuId][$type];
                $personal = $personalOverrides[$menuId][$type] ?? null;

                // 최종 권한 계산 (API AccessService 우선순위와 동일)
                // 1) 개인 DENY → 거부
                // 2) 역할 권한 → 허용
                // 3) 부서 ALLOW → 허용
                // 4) 개인 ALLOW → 허용
                // 5) 기본 → 없음

                $effective = null;
                $source = null;

                if ($personal === 'deny') {
                    $effective = 'deny';
                    $source = 'personal';
                } elseif ($hasRole) {
                    $effective = 'allow';
                    $source = 'role';
                } elseif ($hasDept) {
                    $effective = 'allow';
                    $source = 'department';
                } elseif ($personal === 'allow') {
                    $effective = 'allow';
                    $source = 'personal';
                }

                $permissions[$menuId][$type] = [
                    'effective' => $effective,
                    'source' => $source,
                    'personal' => $personal,
                ];
            }
        }

        return $permissions;
    }

    /**
     * 역할 권한 조회 (Spatie model_has_roles + user_roles + role_has_permissions)
     */
    private function getRolePermissions(int $userId, string $guardName, ?int $tenantId = null): array
    {
        // 1. Spatie model_has_roles 테이블에서 권한 조회
        $spatiePermissions = DB::table('model_has_roles as mhr')
            ->join('role_has_permissions as rhp', 'rhp.role_id', '=', 'mhr.role_id')
            ->join('permissions as p', 'p.id', '=', 'rhp.permission_id')
            ->where('mhr.model_type', User::class)
            ->where('mhr.model_id', $userId)
            ->where('p.guard_name', $guardName)
            ->where('p.name', 'like', 'menu:%')
            ->pluck('p.name')
            ->toArray();

        // 2. user_roles 테이블에서 권한 조회 (테넌트별 역할)
        $userRolesQuery = DB::table('user_roles as ur')
            ->join('role_has_permissions as rhp', 'rhp.role_id', '=', 'ur.role_id')
            ->join('permissions as p', 'p.id', '=', 'rhp.permission_id')
            ->where('ur.user_id', $userId)
            ->whereNull('ur.deleted_at')
            ->where('p.guard_name', $guardName)
            ->where('p.name', 'like', 'menu:%');

        if ($tenantId) {
            $userRolesQuery->where('ur.tenant_id', $tenantId);
        }

        $userRolesPermissions = $userRolesQuery->pluck('p.name')->toArray();

        // 3. 권한 통합 (중복 제거)
        $rolePermissions = array_unique(array_merge($spatiePermissions, $userRolesPermissions));

        $result = [];
        foreach ($rolePermissions as $permName) {
            if (preg_match('/^menu:(\d+)\.(\w+)$/', $permName, $matches)) {
                $menuId = (int) $matches[1];
                $type = $matches[2];

                if (! isset($result[$menuId])) {
                    $result[$menuId] = [];
                }
                $result[$menuId][$type] = true;
            }
        }

        return $result;
    }

    /**
     * 부서 권한 조회 (permission_overrides with Department)
     */
    private function getDepartmentPermissions(int $userId, ?int $tenantId, string $guardName): array
    {
        $now = now();

        $query = DB::table('department_user as du')
            ->join('permission_overrides as po', function ($j) use ($now) {
                $j->on('po.model_id', '=', 'du.department_id')
                    ->where('po.model_type', 'App\\Models\\Tenants\\Department')
                    ->whereNull('po.deleted_at')
                    ->where('po.effect', 1)
                    ->where(function ($w) use ($now) {
                        $w->whereNull('po.effective_from')->orWhere('po.effective_from', '<=', $now);
                    })
                    ->where(function ($w) use ($now) {
                        $w->whereNull('po.effective_to')->orWhere('po.effective_to', '>=', $now);
                    });
            })
            ->join('permissions as p', 'p.id', '=', 'po.permission_id')
            ->whereNull('du.deleted_at')
            ->where('du.user_id', $userId)
            ->where('p.guard_name', $guardName)
            ->where('p.name', 'like', 'menu:%');

        if ($tenantId) {
            $query->where('du.tenant_id', $tenantId)
                ->where('po.tenant_id', $tenantId);
        }

        $deptPermissions = $query->pluck('p.name')->toArray();

        $result = [];
        foreach ($deptPermissions as $permName) {
            if (preg_match('/^menu:(\d+)\.(\w+)$/', $permName, $matches)) {
                $menuId = (int) $matches[1];
                $type = $matches[2];

                if (! isset($result[$menuId])) {
                    $result[$menuId] = [];
                }
                $result[$menuId][$type] = true;
            }
        }

        return $result;
    }

    /**
     * 개인 오버라이드 조회 (permission_overrides with User)
     */
    private function getPersonalOverrides(int $userId, ?int $tenantId, string $guardName): array
    {
        $now = now();

        $query = DB::table('permission_overrides as po')
            ->join('permissions as p', 'p.id', '=', 'po.permission_id')
            ->select('p.name', 'po.effect')
            ->where('po.model_type', User::class)
            ->where('po.model_id', $userId)
            ->where('p.guard_name', $guardName)
            ->where('p.name', 'like', 'menu:%')
            ->whereNull('po.deleted_at')
            ->where(function ($w) use ($now) {
                $w->whereNull('po.effective_from')->orWhere('po.effective_from', '<=', $now);
            })
            ->where(function ($w) use ($now) {
                $w->whereNull('po.effective_to')->orWhere('po.effective_to', '>=', $now);
            });

        if ($tenantId) {
            $query->where('po.tenant_id', $tenantId);
        }

        $userPermissions = $query->get();

        $result = [];
        foreach ($userPermissions as $perm) {
            if (preg_match('/^menu:(\d+)\.(\w+)$/', $perm->name, $matches)) {
                $menuId = (int) $matches[1];
                $type = $matches[2];

                if (! isset($result[$menuId])) {
                    $result[$menuId] = [];
                }
                $result[$menuId][$type] = $perm->effect == 1 ? 'allow' : 'deny';
            }
        }

        return $result;
    }

    /**
     * 특정 메뉴의 특정 권한 토글 (스마트 토글)
     * - 역할/부서 권한 있음 (개인 오버라이드 없음) → 개인 DENY 추가
     * - 개인 DENY → 제거 (역할/부서 권한으로 복원 또는 미설정)
     * - 미설정 (권한 없음) → 개인 ALLOW 추가
     * - 개인 ALLOW → 개인 DENY로 변경
     *
     * @param  int  $userId  사용자 ID
     * @param  int  $menuId  메뉴 ID
     * @param  string  $permissionType  권한 유형
     * @param  int|null  $tenantId  테넌트 ID
     * @param  string  $guardName  Guard 이름 (api 또는 web)
     * @return string|null 토글 후 개인 오버라이드 상태 (null: 미설정, 'allow': 허용, 'deny': 거부)
     */
    public function togglePermission(int $userId, int $menuId, string $permissionType, ?int $tenantId = null, string $guardName = 'api'): ?string
    {
        $permissionName = "menu:{$menuId}.{$permissionType}";

        // 권한 생성 또는 조회
        $permission = Permission::firstOrCreate(
            ['name' => $permissionName, 'guard_name' => $guardName],
            ['tenant_id' => null, 'created_by' => auth()->id()]
        );

        $now = now();

        // 현재 개인 오버라이드 조회
        $currentOverride = DB::table('permission_overrides')
            ->where('model_type', User::class)
            ->where('model_id', $userId)
            ->where('permission_id', $permission->id)
            ->where('tenant_id', $tenantId)
            ->whereNull('deleted_at')
            ->where(function ($w) use ($now) {
                $w->whereNull('effective_from')->orWhere('effective_from', '<=', $now);
            })
            ->where(function ($w) use ($now) {
                $w->whereNull('effective_to')->orWhere('effective_to', '>=', $now);
            })
            ->first();

        // 역할/부서 권한 확인
        $hasRolePermission = $this->hasRolePermission($userId, $permissionName, $tenantId, $guardName);
        $hasDeptPermission = $this->hasDeptPermission($userId, $permissionName, $tenantId, $guardName);
        $hasInheritedPermission = $hasRolePermission || $hasDeptPermission;

        // 스마트 토글 로직
        if ($currentOverride) {
            if ($currentOverride->effect == 0) {
                // 개인 DENY → 제거 (역할/부서로 복원 또는 미설정)
                DB::table('permission_overrides')
                    ->where('id', $currentOverride->id)
                    ->update([
                        'deleted_at' => now(),
                        'deleted_by' => auth()->id(),
                    ]);

                return null;
            } else {
                // 개인 ALLOW → 개인 DENY
                DB::table('permission_overrides')
                    ->where('id', $currentOverride->id)
                    ->update([
                        'effect' => 0, // DENY
                        'updated_at' => now(),
                        'updated_by' => auth()->id(),
                    ]);

                return 'deny';
            }
        } else {
            // 개인 오버라이드 없음
            if ($hasInheritedPermission) {
                // 역할/부서 권한 있음 → 개인 DENY 추가 (오버라이드)
                $this->createPersonalOverride($userId, $permission->id, $tenantId, 0); // DENY

                return 'deny';
            } else {
                // 권한 없음 → 개인 ALLOW 추가
                $this->createPersonalOverride($userId, $permission->id, $tenantId, 1); // ALLOW

                return 'allow';
            }
        }
    }

    /**
     * 역할 권한 존재 여부 확인 (Spatie + user_roles)
     */
    private function hasRolePermission(int $userId, string $permissionName, ?int $tenantId, string $guardName): bool
    {
        // 1. Spatie model_has_roles 테이블에서 확인
        $hasSpatiePermission = DB::table('model_has_roles as mhr')
            ->join('role_has_permissions as rhp', 'rhp.role_id', '=', 'mhr.role_id')
            ->join('permissions as p', 'p.id', '=', 'rhp.permission_id')
            ->where('mhr.model_type', User::class)
            ->where('mhr.model_id', $userId)
            ->where('p.guard_name', $guardName)
            ->where('p.name', $permissionName)
            ->exists();

        if ($hasSpatiePermission) {
            return true;
        }

        // 2. user_roles 테이블에서 확인
        $userRolesQuery = DB::table('user_roles as ur')
            ->join('role_has_permissions as rhp', 'rhp.role_id', '=', 'ur.role_id')
            ->join('permissions as p', 'p.id', '=', 'rhp.permission_id')
            ->where('ur.user_id', $userId)
            ->whereNull('ur.deleted_at')
            ->where('p.guard_name', $guardName)
            ->where('p.name', $permissionName);

        if ($tenantId) {
            $userRolesQuery->where('ur.tenant_id', $tenantId);
        }

        return $userRolesQuery->exists();
    }

    /**
     * 부서 권한 존재 여부 확인
     */
    private function hasDeptPermission(int $userId, string $permissionName, ?int $tenantId, string $guardName): bool
    {
        $now = now();

        $query = DB::table('department_user as du')
            ->join('permission_overrides as po', function ($j) use ($now) {
                $j->on('po.model_id', '=', 'du.department_id')
                    ->where('po.model_type', 'App\\Models\\Tenants\\Department')
                    ->whereNull('po.deleted_at')
                    ->where('po.effect', 1)
                    ->where(function ($w) use ($now) {
                        $w->whereNull('po.effective_from')->orWhere('po.effective_from', '<=', $now);
                    })
                    ->where(function ($w) use ($now) {
                        $w->whereNull('po.effective_to')->orWhere('po.effective_to', '>=', $now);
                    });
            })
            ->join('permissions as p', 'p.id', '=', 'po.permission_id')
            ->whereNull('du.deleted_at')
            ->where('du.user_id', $userId)
            ->where('p.guard_name', $guardName)
            ->where('p.name', $permissionName);

        if ($tenantId) {
            $query->where('du.tenant_id', $tenantId)
                ->where('po.tenant_id', $tenantId);
        }

        return $query->exists();
    }

    /**
     * 개인 오버라이드 생성 (삭제된 레코드 복원 또는 새로 생성)
     */
    private function createPersonalOverride(int $userId, int $permissionId, ?int $tenantId, int $effect): void
    {
        $deletedRecord = DB::table('permission_overrides')
            ->where('model_type', User::class)
            ->where('model_id', $userId)
            ->where('permission_id', $permissionId)
            ->where('tenant_id', $tenantId)
            ->whereNotNull('deleted_at')
            ->first();

        if ($deletedRecord) {
            DB::table('permission_overrides')
                ->where('id', $deletedRecord->id)
                ->update([
                    'effect' => $effect,
                    'deleted_at' => null,
                    'deleted_by' => null,
                    'updated_at' => now(),
                    'updated_by' => auth()->id(),
                ]);
        } else {
            DB::table('permission_overrides')->insert([
                'tenant_id' => $tenantId,
                'model_type' => User::class,
                'model_id' => $userId,
                'permission_id' => $permissionId,
                'effect' => $effect,
                'reason' => null,
                'effective_from' => null,
                'effective_to' => null,
                'created_at' => now(),
                'created_by' => auth()->id(),
                'updated_at' => now(),
                'updated_by' => auth()->id(),
            ]);
        }
    }

    /**
     * 모든 권한 허용 (permission_overrides 테이블 사용)
     * 모든 메뉴에 대해 ALLOW 상태로 설정 (기존 DENY 포함하여 모두 ALLOW로 변경)
     *
     * @param  int  $userId  사용자 ID
     * @param  int|null  $tenantId  테넌트 ID
     * @param  string  $guardName  Guard 이름 (api 또는 web)
     */
    public function allowAllPermissions(int $userId, ?int $tenantId = null, string $guardName = 'api'): void
    {
        $query = Menu::where('is_active', 1);
        if ($tenantId) {
            $query->where('tenant_id', $tenantId);
        }
        $menus = $query->get();

        $now = now();

        foreach ($menus as $menu) {
            foreach ($this->permissionTypes as $type) {
                $permissionName = "menu:{$menu->id}.{$type}";
                $permission = Permission::firstOrCreate(
                    ['name' => $permissionName, 'guard_name' => $guardName],
                    ['tenant_id' => null, 'created_by' => auth()->id()]
                );

                // 현재 유효한 오버라이드 확인 (ALLOW 또는 DENY)
                $existingOverride = DB::table('permission_overrides')
                    ->where('model_type', User::class)
                    ->where('model_id', $userId)
                    ->where('permission_id', $permission->id)
                    ->where('tenant_id', $tenantId)
                    ->whereNull('deleted_at')
                    ->where(function ($w) use ($now) {
                        $w->whereNull('effective_from')->orWhere('effective_from', '<=', $now);
                    })
                    ->where(function ($w) use ($now) {
                        $w->whereNull('effective_to')->orWhere('effective_to', '>=', $now);
                    })
                    ->first();

                if ($existingOverride) {
                    // 기존 오버라이드가 있으면 ALLOW로 변경
                    if ($existingOverride->effect != 1) {
                        DB::table('permission_overrides')
                            ->where('id', $existingOverride->id)
                            ->update([
                                'effect' => 1, // ALLOW
                                'updated_at' => now(),
                                'updated_by' => auth()->id(),
                            ]);
                    }
                } else {
                    // 삭제된 레코드가 있으면 복원, 없으면 생성
                    $deletedRecord = DB::table('permission_overrides')
                        ->where('model_type', User::class)
                        ->where('model_id', $userId)
                        ->where('permission_id', $permission->id)
                        ->where('tenant_id', $tenantId)
                        ->whereNotNull('deleted_at')
                        ->first();

                    if ($deletedRecord) {
                        DB::table('permission_overrides')
                            ->where('id', $deletedRecord->id)
                            ->update([
                                'effect' => 1, // ALLOW
                                'deleted_at' => null,
                                'deleted_by' => null,
                                'updated_at' => now(),
                                'updated_by' => auth()->id(),
                            ]);
                    } else {
                        DB::table('permission_overrides')->insert([
                            'tenant_id' => $tenantId,
                            'model_type' => User::class,
                            'model_id' => $userId,
                            'permission_id' => $permission->id,
                            'effect' => 1, // ALLOW
                            'reason' => null,
                            'effective_from' => null,
                            'effective_to' => null,
                            'created_at' => now(),
                            'created_by' => auth()->id(),
                            'updated_at' => now(),
                            'updated_by' => auth()->id(),
                        ]);
                    }
                }
            }
        }
    }

    /**
     * 모든 권한 초기화 (모두 미설정으로)
     * 모든 오버라이드 레코드를 soft delete하여 미설정 상태로 초기화
     *
     * @param  int  $userId  사용자 ID
     * @param  int|null  $tenantId  테넌트 ID
     * @param  string  $guardName  Guard 이름 (api 또는 web)
     */
    public function denyAllPermissions(int $userId, ?int $tenantId = null, string $guardName = 'api'): void
    {
        $query = Menu::where('is_active', 1);
        if ($tenantId) {
            $query->where('tenant_id', $tenantId);
        }
        $menus = $query->get();

        foreach ($menus as $menu) {
            foreach ($this->permissionTypes as $type) {
                $permissionName = "menu:{$menu->id}.{$type}";
                $permission = Permission::where('name', $permissionName)
                    ->where('guard_name', $guardName)
                    ->first();

                if ($permission) {
                    // Soft delete all overrides (ALLOW or DENY) for this user
                    DB::table('permission_overrides')
                        ->where('model_type', User::class)
                        ->where('model_id', $userId)
                        ->where('permission_id', $permission->id)
                        ->where('tenant_id', $tenantId)
                        ->whereNull('deleted_at')
                        ->update([
                            'deleted_at' => now(),
                            'deleted_by' => auth()->id(),
                        ]);
                }
            }
        }
    }

    /**
     * 기본 권한으로 초기화 (view만 허용)
     *
     * @param  int  $userId  사용자 ID
     * @param  int|null  $tenantId  테넌트 ID
     * @param  string  $guardName  Guard 이름 (api 또는 web)
     */
    public function resetToDefaultPermissions(int $userId, ?int $tenantId = null, string $guardName = 'api'): void
    {
        // 1. 먼저 모든 권한 제거
        $this->denyAllPermissions($userId, $tenantId, $guardName);

        // 2. view 권한만 허용
        $query = Menu::where('is_active', 1);
        if ($tenantId) {
            $query->where('tenant_id', $tenantId);
        }
        $menus = $query->get();

        $now = now();

        foreach ($menus as $menu) {
            $permissionName = "menu:{$menu->id}.view";
            $permission = Permission::firstOrCreate(
                ['name' => $permissionName, 'guard_name' => $guardName],
                ['tenant_id' => null, 'created_by' => auth()->id()]
            );

            // 이미 유효한 ALLOW 오버라이드가 있는지 확인
            $exists = DB::table('permission_overrides')
                ->where('model_type', User::class)
                ->where('model_id', $userId)
                ->where('permission_id', $permission->id)
                ->where('tenant_id', $tenantId)
                ->where('effect', 1)
                ->whereNull('deleted_at')
                ->where(function ($w) use ($now) {
                    $w->whereNull('effective_from')->orWhere('effective_from', '<=', $now);
                })
                ->where(function ($w) use ($now) {
                    $w->whereNull('effective_to')->orWhere('effective_to', '>=', $now);
                })
                ->exists();

            if (! $exists) {
                // 기존에 삭제된 레코드가 있으면 복원, 없으면 생성
                $existingRecord = DB::table('permission_overrides')
                    ->where('model_type', User::class)
                    ->where('model_id', $userId)
                    ->where('permission_id', $permission->id)
                    ->where('tenant_id', $tenantId)
                    ->where('effect', 1)
                    ->first();

                if ($existingRecord) {
                    DB::table('permission_overrides')
                        ->where('id', $existingRecord->id)
                        ->update([
                            'deleted_at' => null,
                            'deleted_by' => null,
                            'updated_at' => now(),
                            'updated_by' => auth()->id(),
                        ]);
                } else {
                    DB::table('permission_overrides')->insert([
                        'tenant_id' => $tenantId,
                        'model_type' => User::class,
                        'model_id' => $userId,
                        'permission_id' => $permission->id,
                        'effect' => 1, // ALLOW
                        'reason' => null,
                        'effective_from' => null,
                        'effective_to' => null,
                        'created_at' => now(),
                        'created_by' => auth()->id(),
                        'updated_at' => now(),
                        'updated_by' => auth()->id(),
                    ]);
                }
            }
        }
    }

    /**
     * 메뉴 트리 조회 (권한 매트릭스 표시용)
     *
     * @param  int|null  $tenantId  테넌트 ID
     * @return \Illuminate\Support\Collection 메뉴 트리
     */
    public function getMenuTree(?int $tenantId = null): \Illuminate\Support\Collection
    {
        // TenantScope를 비활성화하고 명시적으로 tenant_id 필터 적용
        // (HQ 관리자가 다른 테넌트의 메뉴를 조회할 수 있도록)
        $query = Menu::withoutGlobalScope(TenantScope::class)
            ->with('parent')
            ->where('is_active', 1);

        if ($tenantId) {
            $query->where('tenant_id', $tenantId);
        }

        $allMenus = $query->orderBy('sort_order', 'asc')
            ->orderBy('id', 'asc')
            ->get();

        // depth 계산하여 플랫한 구조로 변환
        return $this->flattenMenuTree($allMenus);
    }

    /**
     * 트리 구조를 플랫한 배열로 변환 (depth 정보 포함)
     *
     * @param  \Illuminate\Support\Collection  $menus  메뉴 컬렉션
     * @param  int|null  $parentId  부모 메뉴 ID
     * @param  int  $depth  현재 깊이
     */
    private function flattenMenuTree(\Illuminate\Support\Collection $menus, ?int $parentId = null, int $depth = 0): \Illuminate\Support\Collection
    {
        $result = collect();

        $filteredMenus = $menus->where('parent_id', $parentId)->sortBy('sort_order');

        foreach ($filteredMenus as $menu) {
            $menu->depth = $depth;

            // 자식 메뉴 존재 여부 확인
            $menu->has_children = $menus->where('parent_id', $menu->id)->count() > 0;

            $result->push($menu);

            // 자식 메뉴 재귀적으로 추가
            $children = $this->flattenMenuTree($menus, $menu->id, $depth + 1);
            $result = $result->merge($children);
        }

        return $result;
    }

    /**
     * 특정 사용자의 활성 메뉴 권한 확인 (permission_overrides 테이블 사용)
     *
     * @param  int  $userId  사용자 ID
     * @param  int  $menuId  메뉴 ID
     * @param  string  $permissionType  권한 유형
     * @param  string  $guardName  Guard 이름 (api 또는 web)
     * @return bool 권한 존재 여부
     */
    public function hasPermission(int $userId, int $menuId, string $permissionType, string $guardName = 'api'): bool
    {
        $permissionName = "menu:{$menuId}.{$permissionType}";
        $now = now();

        return DB::table('permission_overrides as po')
            ->join('permissions as p', 'p.id', '=', 'po.permission_id')
            ->where('po.model_type', User::class)
            ->where('po.model_id', $userId)
            ->where('po.effect', 1)
            ->where('p.name', $permissionName)
            ->where('p.guard_name', $guardName)
            ->whereNull('po.deleted_at')
            ->where(function ($w) use ($now) {
                $w->whereNull('po.effective_from')->orWhere('po.effective_from', '<=', $now);
            })
            ->where(function ($w) use ($now) {
                $w->whereNull('po.effective_to')->orWhere('po.effective_to', '>=', $now);
            })
            ->exists();
    }

    /**
     * 대상 사용자가 슈퍼관리자인지 검증 (일반관리자는 슈퍼관리자 수정 불가)
     *
     * @param  int  $targetUserId  대상 사용자 ID
     * @return bool true면 수정 가능, false면 수정 불가
     */
    public function canModifyUser(int $targetUserId): bool
    {
        // withTrashed()를 사용하여 일관성 유지
        $targetUser = User::withTrashed()->find($targetUserId);
        $currentUser = auth()->user();

        // 대상 사용자가 슈퍼관리자이고 현재 사용자가 슈퍼관리자가 아니면 수정 불가
        if ($targetUser?->is_super_admin && ! $currentUser?->is_super_admin) {
            return false;
        }

        return true;
    }

    /**
     * 테넌트별 사용자 목록 조회 (권한 개수 포함)
     * 일반관리자는 슈퍼관리자가 목록에서 제외됨
     *
     * @param  int  $tenantId  테넌트 ID
     * @return \Illuminate\Support\Collection 사용자 목록
     */
    public function getUsersByTenant(int $tenantId): \Illuminate\Support\Collection
    {
        $currentUser = auth()->user();

        $query = User::whereHas('tenants', function ($query) use ($tenantId) {
            $query->where('tenants.id', $tenantId)
                ->where('user_tenants.is_active', true);
        })
            ->where('is_active', true);

        // 일반관리자는 슈퍼관리자를 볼 수 없음
        if (! $currentUser?->is_super_admin) {
            $query->where('is_super_admin', false);
        }

        $users = $query->orderBy('name')->get();

        // 각 사용자별 권한 개수 계산
        $now = now();
        foreach ($users as $user) {
            $permissionCounts = $this->getUserPermissionCounts($user->id, $tenantId, $now);
            $user->web_permission_count = $permissionCounts['web'];
            $user->api_permission_count = $permissionCounts['api'];
        }

        return $users;
    }

    /**
     * 사용자별 guard별 권한 개수 조회 (역할 + 부서 + 개인 오버라이드 통합)
     *
     * @param  int  $userId  사용자 ID
     * @param  int  $tenantId  테넌트 ID
     * @param  \Carbon\Carbon  $now  현재 시간
     * @return array ['web' => int, 'api' => int]
     */
    private function getUserPermissionCounts(int $userId, int $tenantId, $now): array
    {
        $result = ['web' => 0, 'api' => 0];

        foreach (['web', 'api'] as $guardName) {
            // 1-1. Spatie 역할 권한 (model_has_roles)
            $spatieRolePermissions = DB::table('model_has_roles as mhr')
                ->join('role_has_permissions as rhp', 'rhp.role_id', '=', 'mhr.role_id')
                ->join('permissions as p', 'p.id', '=', 'rhp.permission_id')
                ->where('mhr.model_type', User::class)
                ->where('mhr.model_id', $userId)
                ->where('p.guard_name', $guardName)
                ->where('p.name', 'like', 'menu:%')
                ->pluck('p.name')
                ->toArray();

            // 1-2. 테넌트별 역할 권한 (user_roles)
            $userRolesPermissions = DB::table('user_roles as ur')
                ->join('role_has_permissions as rhp', 'rhp.role_id', '=', 'ur.role_id')
                ->join('permissions as p', 'p.id', '=', 'rhp.permission_id')
                ->where('ur.user_id', $userId)
                ->where('ur.tenant_id', $tenantId)
                ->whereNull('ur.deleted_at')
                ->where('p.guard_name', $guardName)
                ->where('p.name', 'like', 'menu:%')
                ->pluck('p.name')
                ->toArray();

            // 역할 권한 통합
            $rolePermissions = array_unique(array_merge($spatieRolePermissions, $userRolesPermissions));

            // 2. 부서 권한
            $deptPermissions = DB::table('department_user as du')
                ->join('permission_overrides as po', function ($j) use ($now, $tenantId) {
                    $j->on('po.model_id', '=', 'du.department_id')
                        ->where('po.model_type', 'App\\Models\\Tenants\\Department')
                        ->where('po.tenant_id', $tenantId)
                        ->whereNull('po.deleted_at')
                        ->where('po.effect', 1)
                        ->where(function ($w) use ($now) {
                            $w->whereNull('po.effective_from')->orWhere('po.effective_from', '<=', $now);
                        })
                        ->where(function ($w) use ($now) {
                            $w->whereNull('po.effective_to')->orWhere('po.effective_to', '>=', $now);
                        });
                })
                ->join('permissions as p', 'p.id', '=', 'po.permission_id')
                ->whereNull('du.deleted_at')
                ->where('du.user_id', $userId)
                ->where('du.tenant_id', $tenantId)
                ->where('p.guard_name', $guardName)
                ->where('p.name', 'like', 'menu:%')
                ->pluck('p.name')
                ->toArray();

            // 3. 개인 오버라이드 (ALLOW)
            $personalAllows = DB::table('permission_overrides as po')
                ->join('permissions as p', 'p.id', '=', 'po.permission_id')
                ->where('po.model_type', User::class)
                ->where('po.model_id', $userId)
                ->where('po.tenant_id', $tenantId)
                ->where('po.effect', 1)
                ->whereNull('po.deleted_at')
                ->where(function ($w) use ($now) {
                    $w->whereNull('po.effective_from')->orWhere('po.effective_from', '<=', $now);
                })
                ->where(function ($w) use ($now) {
                    $w->whereNull('po.effective_to')->orWhere('po.effective_to', '>=', $now);
                })
                ->where('p.guard_name', $guardName)
                ->where('p.name', 'like', 'menu:%')
                ->pluck('p.name')
                ->toArray();

            // 4. 개인 오버라이드 (DENY) - 제외할 권한
            $personalDenies = DB::table('permission_overrides as po')
                ->join('permissions as p', 'p.id', '=', 'po.permission_id')
                ->where('po.model_type', User::class)
                ->where('po.model_id', $userId)
                ->where('po.tenant_id', $tenantId)
                ->where('po.effect', 0)
                ->whereNull('po.deleted_at')
                ->where(function ($w) use ($now) {
                    $w->whereNull('po.effective_from')->orWhere('po.effective_from', '<=', $now);
                })
                ->where(function ($w) use ($now) {
                    $w->whereNull('po.effective_to')->orWhere('po.effective_to', '>=', $now);
                })
                ->where('p.guard_name', $guardName)
                ->where('p.name', 'like', 'menu:%')
                ->pluck('p.name')
                ->toArray();

            // 통합: (역할 OR 부서 OR 개인ALLOW) - 개인DENY
            $allAllowed = array_unique(array_merge($rolePermissions, $deptPermissions, $personalAllows));
            $effectivePermissions = array_diff($allAllowed, $personalDenies);

            $result[$guardName] = count($effectivePermissions);
        }

        return $result;
    }
}
