<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Session;
use App\Core\Tenant;
use App\Models\Branch;
use App\Models\Company;
use App\Models\Role;
use App\Models\User;
use App\Services\AuditService;
use App\Services\UserCredentialsEmailService;

class UserController extends Controller
{
    public function index(Request $request): void
    {
        $companyId = (int) tenant_id();
        $model = new User();
        $roleModel = new Role();
        $canManageSuperadmin = is_superadmin();
        $roles = $roleModel->activeRoles($canManageSuperadmin);
        $permissionsCatalog = $roleModel->permissionsCatalog($canManageSuperadmin);
        $visiblePermissionIds = [];
        foreach ($permissionsCatalog as $permission) {
            $permissionId = (int) ($permission['id'] ?? 0);
            if ($permissionId > 0) {
                $visiblePermissionIds[$permissionId] = true;
            }
        }

        $rolePermissionMap = [];
        foreach ($roles as $role) {
            $roleId = (int) ($role['id'] ?? 0);
            $assignedPermissionIds = $roleModel->permissionIdsByRole($roleId);
            $rolePermissionMap[$roleId] = array_values(array_filter(
                $assignedPermissionIds,
                static fn (int $permissionId): bool => isset($visiblePermissionIds[$permissionId])
            ));
        }

        $this->render('usuarios/index', [
            'title' => 'Usuarios',
            'users' => $model->listByCompany($companyId),
            'roles' => $roles,
            'branches' => (new Branch())->all(['activa' => 1], $companyId, 'nombre ASC'),
            'permissionsCatalog' => $permissionsCatalog,
            'rolePermissionMap' => $rolePermissionMap,
        ]);
    }

    public function store(Request $request): never
    {
        $companyId = (int) Tenant::companyId();
        $name = trim((string) $request->input('nombre', ''));
        $email = strtolower(trim((string) $request->input('email', '')));
        $password = (string) $request->input('password', '');
        $roleId = (int) $request->input('rol_id', 0);
        $branchId = (int) $request->input('sucursal_id', 0);

        Session::setOldInput($request->all());

        if ($name === '' || $email === '' || $password === '' || $roleId <= 0) {
            flash('error', 'Todos los campos son obligatorios.');
            redirect('usuarios');
        }

        if ($branchId > 0 && (new Branch())->findById($branchId, $companyId) === null) {
            flash('error', 'La sucursal seleccionada no pertenece a la empresa.');
            redirect('usuarios');
        }

        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            flash('error', 'Correo inválido.');
            redirect('usuarios');
        }

        if (strlen($password) < 8) {
            flash('error', 'La contraseña debe tener al menos 8 caracteres.');
            redirect('usuarios');
        }

        $roleModel = new Role();
        $assignableRole = $roleModel->findActiveById($roleId, is_superadmin());
        if ($assignableRole === null) {
            flash('error', 'El rol seleccionado no está permitido.');
            redirect('usuarios');
        }

        $model = new User();
        if ($model->existsByEmail($email)) {
            flash('error', 'Ya existe un usuario con ese correo.');
            redirect('usuarios');
        }

        $userId = $model->create([
            'empresa_id' => $companyId,
            'sucursal_id' => $branchId > 0 ? $branchId : null,
            'rol_id' => $roleId,
            'nombre' => $name,
            'email' => $email,
            'password' => password_hash($password, PASSWORD_DEFAULT),
            'activo' => 1,
            'created_at' => date('Y-m-d H:i:s'),
        ]);

        $company = (new Company())->findById($companyId);
        $mailResult = (new UserCredentialsEmailService())->send([
            'email' => $email,
            'user_name' => $name,
            'password' => $password,
            'company_name' => (string) ($company['nombre'] ?? 'Veltrix POS'),
            'company_slug' => (string) ($company['slug'] ?? ''),
        ]);

        Session::clearOldInput();
        AuditService::track('usuarios.crear', 'Usuario creado ID: ' . $userId);
        if ((bool) ($mailResult['ok'] ?? false)) {
            flash('success', 'Usuario registrado correctamente. Se envió correo de acceso.');
        } else {
            flash('success', 'Usuario registrado correctamente. Aviso correo: ' . trim((string) ($mailResult['error'] ?? 'No se pudo enviar.')));
        }
        redirect('usuarios');
    }

    public function updateRolePermissions(Request $request): never
    {
        $roleId = (int) $request->input('rol_id', 0);
        $selectedPermissions = (array) $request->input('permisos', []);
        $canManageSuperadmin = is_superadmin();

        if ($roleId <= 0) {
            flash('error', 'Rol inválido para actualizar permisos.');
            redirect('usuarios');
        }

        $roleModel = new Role();
        $role = $roleModel->findActiveById($roleId, $canManageSuperadmin);
        if ($role === null) {
            flash('error', 'El rol seleccionado no existe o no está permitido.');
            redirect('usuarios');
        }

        $catalog = $roleModel->permissionsCatalog($canManageSuperadmin);
        $validPermissionIds = array_map(
            static fn (array $permission): int => (int) ($permission['id'] ?? 0),
            $catalog
        );
        $validPermissionIds = array_values(array_unique(array_filter($validPermissionIds, static fn (int $id): bool => $id > 0)));

        $requestedPermissionIds = [];
        foreach ($selectedPermissions as $permissionId) {
            $value = (int) $permissionId;
            if ($value > 0 && in_array($value, $validPermissionIds, true)) {
                $requestedPermissionIds[] = $value;
            }
        }

        try {
            $roleModel->syncPermissions($roleId, $requestedPermissionIds);

            Session::forget('permissions_cache');
            AuditService::track(
                'roles.permisos.actualizar',
                'Rol ID: ' . $roleId . ' actualizado con ' . count($requestedPermissionIds) . ' permisos'
            );
            flash('success', 'Permisos del rol actualizados correctamente.');
            redirect('usuarios');
        } catch (\Throwable $e) {
            flash('error', 'No fue posible actualizar los permisos del rol: ' . $e->getMessage());
            redirect('usuarios');
        }
    }
}
