<?php
declare(strict_types=1);

namespace App\Modules\Users\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Core\App;
use App\Core\Registries\PermissionRegistry;
use App\Modules\Users\Models\Employee;
use App\Modules\Roles\Models\Role;
use App\Modules\Users\Services\PermissionAuditService;

class UserPermissionController extends Controller
{
    public function preview(Request $request): Response
    {
        $roleIds = $request->get('roles', []);
        if (!is_array($roleIds) || empty($roleIds)) {
            return $this->json(['permissions' => [], 'count' => 0]);
        }

        $db = App::getInstance()->db();
        $placeholders = implode(',', array_fill(0, count($roleIds), '?'));
        $params = array_map('intval', $roleIds);

        $perms = $db->select(
            "SELECT DISTINCT permission_key FROM role_permissions WHERE role_id IN ({$placeholders})",
            $params
        );

        $permKeys = array_column($perms, 'permission_key');
        $hasWildcard = in_array('*', $permKeys, true);

        return $this->json([
            'permissions' => $permKeys,
            'count'       => $hasWildcard ? -1 : count($permKeys),
            'wildcard'    => $hasWildcard,
        ]);
    }

    public function edit(Request $request, string $id): Response
    {
        $employee = Employee::find((int) $id);
        if (!$employee) {
            return $this->redirect('/users')->withError('الموظف غير موجود');
        }

        $allPermissions = PermissionRegistry::getAllGrouped();
        $allRoles = Role::allActive();
        $employeeRoles = $employee->getRolesWithNames();
        $currentRoleIds = array_column($employeeRoles, 'id');

        $roleExpirations = [];
        foreach ($employeeRoles as $er) {
            $roleExpirations[(int) $er['id']] = $er['expires_at'] ?? '';
        }

        $db = App::getInstance()->db();
        $rolePermMap = [];
        foreach ($employeeRoles as $er) {
            $perms = $db->select(
                "SELECT permission_key FROM role_permissions WHERE role_id = ?",
                [(int) $er['id']]
            );
            foreach ($perms as $p) {
                $rolePermMap[$p['permission_key']][] = $er['name_ar'];
            }
        }

        $directPerms = $employee->getDirectPermissions();
        $directMap = [];
        foreach ($directPerms as $dp) {
            $directMap[$dp['permission_key']] = (int) $dp['is_denied'] === 1 ? 'deny' : 'grant';
        }

        return $this->view('Users.Views.permissions', [
            'employee'        => $employee,
            'allPermissions'  => $allPermissions,
            'allRoles'        => $allRoles,
            'currentRoleIds'  => $currentRoleIds,
            'roleExpirations' => $roleExpirations,
            'rolePermMap'     => $rolePermMap,
            'directMap'       => $directMap,
        ]);
    }

    public function update(Request $request, string $id): Response
    {
        $employee = Employee::find((int) $id);
        if (!$employee) {
            return $this->redirect('/users')->withError('الموظف غير موجود');
        }

        $db = App::getInstance()->db();
        $currentEmp = App::getInstance()->currentEmployee();
        $grantedBy = $currentEmp ? (int) $currentEmp->id : 0;

        $oldRoleIds = array_column($employee->getRolesWithNames(), 'id');
        $oldRoleCodes = [];
        foreach ($employee->getRolesWithNames() as $r) {
            $oldRoleCodes[(int) $r['id']] = $r['role_code'];
        }

        $db->delete('employee_roles', '`employee_id` = ?', [$employee->id]);
        $roleIds = $request->post('roles', []);
        $roleExpires = $request->post('role_expires', []);
        $newRoleIds = [];
        if (is_array($roleIds)) {
            foreach ($roleIds as $roleId) {
                $expiresAt = $roleExpires[$roleId] ?? null;
                $db->insert('employee_roles', [
                    'employee_id' => (int) $employee->id,
                    'role_id'     => (int) $roleId,
                    'assigned_at' => date('Y-m-d H:i:s'),
                    'assigned_by' => $grantedBy,
                    'expires_at'  => ($expiresAt && $expiresAt !== '') ? $expiresAt : null,
                    'is_active'   => 1,
                ]);
                $newRoleIds[] = (int) $roleId;
            }
        }

        $allRolesMap = [];
        foreach (Role::allActive() as $r) {
            $allRolesMap[(int) $r->id] = $r->role_code;
        }

        $addedRoles = array_diff($newRoleIds, $oldRoleIds);
        $removedRoles = array_diff($oldRoleIds, $newRoleIds);
        foreach ($addedRoles as $rid) {
            PermissionAuditService::logRoleAssigned((int) $employee->id, $allRolesMap[$rid] ?? (string) $rid, $grantedBy);
        }
        foreach ($removedRoles as $rid) {
            PermissionAuditService::logRoleRemoved((int) $employee->id, $oldRoleCodes[$rid] ?? (string) $rid, $grantedBy);
        }

        $permStates = $request->post('perm_state', []);
        $grants = [];
        $denials = [];
        if (is_array($permStates)) {
            foreach ($permStates as $key => $state) {
                if ($state === 'grant') {
                    $grants[] = $key;
                } elseif ($state === 'deny') {
                    $denials[] = $key;
                }
            }
        }

        $oldDirect = $employee->getDirectPermissions();
        $oldDirectMap = [];
        foreach ($oldDirect as $dp) {
            $oldDirectMap[$dp['permission_key']] = (int) $dp['is_denied'] === 1 ? 'deny' : 'grant';
        }

        $employee->syncDirectPermissions($grants, $denials, $grantedBy);

        foreach ($grants as $g) {
            if (($oldDirectMap[$g] ?? null) !== 'grant') {
                PermissionAuditService::logPermissionGranted((int) $employee->id, $g, $grantedBy);
            }
        }
        foreach ($denials as $d) {
            if (($oldDirectMap[$d] ?? null) !== 'deny') {
                PermissionAuditService::logPermissionDenied((int) $employee->id, $d, $grantedBy);
            }
        }

        return $this->redirect("/users/{$id}/permissions")->withSuccess('تم تحديث الصلاحيات بنجاح');
    }
}
