<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Api\ApiController;
use App\Models\Usuario;
use App\Models\Perfil;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;

class UsuarioController extends ApiController
{
    /**
     * Listar usuarios con filtros y paginación
     * GET /api/v1/usuarios
     */
    public function index(Request $request): JsonResponse
    {
        return $this->ejecutar(function () use ($request) {

            $query = Usuario::with(['perfil', 'empresas'])
                ->select([
                    'usu_id',
                    'usu_nombre',
                    'usu_apellido',
                    'usu_cedula',
                    'usu_usuario',
                    'usu_email',
                    'per_id',
                    'usu_estado',
                    'fecha_ingreso',
                    'usu_ultimo_login',
                ]);

            // Filtro por búsqueda general
            if ($request->filled('buscar')) {
                $query->buscar($request->buscar);
            }

            // Filtro por perfil
            if ($request->filled('perfil_id')) {
                $query->porPerfil($request->perfil_id);
            }

            // Filtro por estado
            if ($request->filled('estado')) {
                $query->where('usu_estado', $request->estado);
            }

            // Filtro por empresa
            if ($request->filled('empresa_id')) {
                $query->whereHas('empresas', function ($q) use ($request) {
                    $q->where('empresa.emp_id', $request->empresa_id);
                });
            }

            // Ordenamiento
            $ordenCampo = $request->input('orden_campo', 'usu_nombre');
            $ordenDir = $request->input('orden_dir', 'asc');
            $query->orderBy($ordenCampo, $ordenDir);

            // Paginación
            $perPage = min($request->input('per_page', 20), 100);
            $usuarios = $query->paginate($perPage);

            return $this->successResponse([
                'usuarios' => $usuarios->items(),
                'paginacion' => [
                    'total' => $usuarios->total(),
                    'per_page' => $usuarios->perPage(),
                    'current_page' => $usuarios->currentPage(),
                    'last_page' => $usuarios->lastPage(),
                    'from' => $usuarios->firstItem(),
                    'to' => $usuarios->lastItem(),
                ],
            ]);

        }, 'Error listando usuarios');
    }

    /**
     * Ver detalle de usuario
     * GET /api/v1/usuarios/{id}
     */
    public function show(int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($id) {

            $usuario = Usuario::with(['perfil', 'empresas', 'creadoPor', 'modificadoPor'])
                ->findOrFail($id);

            return $this->successResponse([
                'usuario' => [
                    'id' => $usuario->usu_id,
                    'nombre' => $usuario->usu_nombre,
                    'apellido' => $usuario->usu_apellido,
                    'nombre_completo' => $usuario->nombre_completo,
                    'cedula' => $usuario->usu_cedula,
                    'email' => $usuario->usu_email,
                    'usuario' => $usuario->usu_usuario,
                    'fecha_nacimiento' => $usuario->usu_fecha_nac?->format('Y-m-d'),
                    'fecha_ingreso' => $usuario->fecha_ingreso?->format('Y-m-d'),
                    'ultimo_login' => $usuario->usu_ultimo_login?->toIso8601String(),
                    'estado' => $usuario->usu_estado,
                    'cambio_password' => $usuario->usu_cambio_password,
                    'perfil' => [
                        'id' => $usuario->perfil->per_id,
                        'nombre' => $usuario->perfil->per_nombre,
                    ],
                    'empresas' => $usuario->empresas->map(fn($e) => [
                        'id' => $e->emp_id,
                        'nombre' => $e->emp_nombre,
                    ]),
                    'auditoria' => [
                        'creado_por' => $usuario->creadoPor?->nombre_completo,
                        'fecha_creacion' => $usuario->fecha_crea,
                        'modificado_por' => $usuario->modificadoPor?->nombre_completo,
                        'fecha_modificacion' => $usuario->fecha_modifica,
                    ],
                ],
            ]);

        }, 'Error obteniendo usuario');
    }

    /**
     * Crear usuario
     * POST /api/v1/usuarios
     */
    public function store(Request $request): JsonResponse
    {
        return $this->ejecutar(function () use ($request) {

            // Validación
            $request->validate([
                'nombre' => 'required|string|max:50',
                'apellido' => 'required|string|max:50',
                'cedula' => [
                    'required',
                    'string',
                    'size:10',
                    Rule::unique('usuarios', 'usu_cedula'),
                ],
                'email' => [
                    'required',
                    'email',
                    'max:250',
                    Rule::unique('usuarios', 'usu_email'),
                ],
                'perfil_id' => 'required|integer|exists:perfil,per_id',
                'fecha_nacimiento' => 'nullable|date|before:today',
                'fecha_ingreso' => 'nullable|date',
                'empresas' => 'nullable|array',
                'empresas.*' => 'integer|exists:empresa,emp_id',
            ], [
                'cedula.size' => 'La cédula debe tener 10 dígitos',
                'cedula.unique' => 'La cédula ya está registrada',
                'email.unique' => 'El correo ya está registrado',
                'perfil_id.exists' => 'El perfil seleccionado no existe',
            ]);

            // Validar cédula ecuatoriana
            if (!$this->validarCedulaEcuatoriana($request->cedula)) {
                return $this->validationErrorResponse(
                    ['cedula' => ['La cédula no es válida']],
                    'Datos de entrada inválidos'
                );
            }

            // Generar username automático
            $username = $this->generarUsername($request->nombre, $request->apellido);

            // Generar contraseña temporal
            $passwordTemporal = Str::random(12);

            DB::beginTransaction();
            try {
                // Crear usuario (usar password_laravel igual que en web)
                $usuario = Usuario::create([
                    'usu_nombre' => $request->nombre,
                    'usu_apellido' => $request->apellido,
                    'usu_cedula' => $request->cedula,
                    'usu_email' => $request->email,
                    'usu_usuario' => $username,
                    'password_laravel' => Hash::make($passwordTemporal),
                    'per_id' => $request->perfil_id,
                    'usu_estado' => 1,
                    'usu_fecha_nac' => $request->fecha_nacimiento,
                    'fecha_ingreso' => $request->fecha_ingreso ?? now(),
                    'usu_cambio_password' => true,
                    'usu_intentos_fallidos' => 0,
                ]);

                // Asignar empresas
                if ($request->filled('empresas')) {
                    $usuario->empresas()->sync($request->empresas);
                }

                // TODO: Enviar correo con credenciales
                // Mail::to($usuario->usu_email)->queue(new CredencialesNuevoUsuario($usuario, $passwordTemporal));

                DB::commit();

                // Registrar auditoría
                $this->registrarAuditoria('CREAR', 'usuarios', $usuario->usu_id, null, $usuario->toArray());

                return $this->createdResponse([
                    'usuario' => [
                        'id' => $usuario->usu_id,
                        'nombre_completo' => $usuario->nombre_completo,
                        'usuario' => $usuario->usu_usuario,
                        'email' => $usuario->usu_email,
                    ],
                    'password_temporal' => $passwordTemporal,
                    'mensaje' => 'Usuario debe cambiar contraseña en primer inicio',
                ], 'Usuario creado exitosamente');

            } catch (\Exception $e) {
                DB::rollBack();
                throw $e;
            }

        }, 'Error creando usuario');
    }

    /**
     * Actualizar usuario
     * PUT /api/v1/usuarios/{id}
     */
    public function update(Request $request, int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($request, $id) {

            $usuario = Usuario::findOrFail($id);
            $datosAnteriores = $usuario->toArray();

            // Validación
            $request->validate([
                'nombre' => 'sometimes|required|string|max:50',
                'apellido' => 'sometimes|required|string|max:50',
                'email' => [
                    'sometimes',
                    'required',
                    'email',
                    'max:250',
                    Rule::unique('usuarios', 'usu_email')->ignore($id, 'usu_id'),
                ],
                'perfil_id' => 'sometimes|required|integer|exists:perfil,per_id',
                'fecha_nacimiento' => 'nullable|date|before:today',
                'fecha_ingreso' => 'nullable|date',
                'empresas' => 'nullable|array',
                'empresas.*' => 'integer|exists:empresa,emp_id',
            ]);

            DB::beginTransaction();
            try {
                // Actualizar campos
                $usuario->fill([
                    'usu_nombre' => $request->input('nombre', $usuario->usu_nombre),
                    'usu_apellido' => $request->input('apellido', $usuario->usu_apellido),
                    'usu_email' => $request->input('email', $usuario->usu_email),
                    'per_id' => $request->input('perfil_id', $usuario->per_id),
                    'usu_fecha_nac' => $request->input('fecha_nacimiento', $usuario->usu_fecha_nac),
                    'fecha_ingreso' => $request->input('fecha_ingreso', $usuario->fecha_ingreso),
                ]);
                $usuario->save();

                // Actualizar empresas si se envían
                if ($request->has('empresas')) {
                    $usuario->empresas()->sync($request->empresas);
                }

                DB::commit();

                // Registrar auditoría
                $this->registrarAuditoria('ACTUALIZAR', 'usuarios', $usuario->usu_id, $datosAnteriores, $usuario->toArray());

                return $this->successResponse([
                    'usuario' => [
                        'id' => $usuario->usu_id,
                        'nombre_completo' => $usuario->nombre_completo,
                        'email' => $usuario->usu_email,
                    ],
                ], 'Usuario actualizado exitosamente');

            } catch (\Exception $e) {
                DB::rollBack();
                throw $e;
            }

        }, 'Error actualizando usuario');
    }

    /**
     * Activar/Desactivar usuario
     * PATCH /api/v1/usuarios/{id}/toggle-estado
     */
    public function toggleEstado(int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($id) {

            $usuario = Usuario::findOrFail($id);

            // No permitir desactivar el último SISTEMAS activo
            if ($usuario->usu_estado == 1) {
                $perfil = Perfil::find($usuario->per_id);
                if ($perfil && strtoupper($perfil->per_nombre) === 'SISTEMAS') {
                    $sistemasActivos = Usuario::where('per_id', $usuario->per_id)
                        ->where('usu_estado', 1)
                        ->count();

                    if ($sistemasActivos <= 1) {
                        return $this->errorResponse(
                            'No se puede desactivar el último usuario SISTEMAS',
                            400
                        );
                    }
                }
            }

            $estadoAnterior = $usuario->usu_estado;
            $usuario->usu_estado = $usuario->usu_estado == 1 ? 0 : 1;
            $usuario->save();

            // Si se desactiva, cerrar sesiones
            if ($usuario->usu_estado == 0) {
                $usuario->tokens()->delete();
            }

            // Registrar auditoría
            $this->registrarAuditoria(
                $usuario->usu_estado == 1 ? 'ACTIVAR' : 'DESACTIVAR',
                'usuarios',
                $usuario->usu_id,
                ['estado' => $estadoAnterior],
                ['estado' => $usuario->usu_estado]
            );

            $mensaje = $usuario->usu_estado == 1
                ? 'Usuario activado exitosamente'
                : 'Usuario desactivado exitosamente';

            return $this->successResponse([
                'id' => $usuario->usu_id,
                'estado' => $usuario->usu_estado,
            ], $mensaje);

        }, 'Error cambiando estado de usuario');
    }

    /**
     * Reset de contraseña por administrador
     * POST /api/v1/usuarios/{id}/reset-password
     */
    public function resetPassword(int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($id) {

            $usuario = Usuario::findOrFail($id);

            // Generar contraseña temporal
            $passwordTemporal = Str::random(12);

            // Usar password_laravel igual que en web
            $usuario->update([
                'password_laravel' => Hash::make($passwordTemporal),
                'usu_cambio_password' => true,
                'usu_intentos_fallidos' => 0,
                'usu_bloqueado_hasta' => null,
            ]);

            // Cerrar sesiones activas
            $usuario->tokens()->delete();

            // TODO: Enviar correo
            // Mail::to($usuario->usu_email)->queue(new PasswordReseteado($usuario, $passwordTemporal));

            // Registrar auditoría
            $this->registrarAuditoria('RESET_PASSWORD_ADMIN', 'usuarios', $usuario->usu_id);

            return $this->successResponse([
                'id' => $usuario->usu_id,
                'password_temporal' => $passwordTemporal,
                'mensaje' => 'Usuario debe cambiar contraseña en próximo inicio',
            ], 'Contraseña reseteada exitosamente');

        }, 'Error reseteando contraseña');
    }

    /**
     * Desbloquear usuario bloqueado por intentos fallidos
     * PATCH /api/v1/usuarios/{id}/desbloquear
     */
    public function desbloquear(int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($id) {

            $usuario = Usuario::findOrFail($id);

            // Verificar si está bloqueado
            if (!$usuario->estaBloqueado()) {
                return $this->errorResponse('El usuario no está bloqueado', 400);
            }

            $usuario->update([
                'usu_bloqueado_hasta' => null,
                'usu_intentos_fallidos' => 0,
            ]);

            // Registrar auditoría
            $this->registrarAuditoria('DESBLOQUEAR', 'usuarios', $usuario->usu_id);

            return $this->successResponse([
                'id' => $usuario->usu_id,
                'nombre_completo' => $usuario->nombre_completo,
            ], 'Usuario desbloqueado exitosamente');

        }, 'Error desbloqueando usuario');
    }

    /**
     * Forzar cambio de contraseña en próximo login
     * PATCH /api/v1/usuarios/{id}/forzar-cambio-password
     */
    public function forzarCambioPassword(int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($id) {

            $usuario = Usuario::findOrFail($id);

            $usuario->update([
                'usu_cambio_password' => true,
            ]);

            // Registrar auditoría
            $this->registrarAuditoria('FORZAR_CAMBIO_PASSWORD', 'usuarios', $usuario->usu_id);

            return $this->successResponse([
                'id' => $usuario->usu_id,
                'nombre_completo' => $usuario->nombre_completo,
            ], 'Se solicitará cambio de contraseña en el próximo inicio de sesión');

        }, 'Error forzando cambio de contraseña');
    }

    /**
     * Validar cédula ecuatoriana
     */
    private function validarCedulaEcuatoriana(string $cedula): bool
    {
        if (strlen($cedula) !== 10) {
            return false;
        }

        if (!ctype_digit($cedula)) {
            return false;
        }

        $provincia = (int) substr($cedula, 0, 2);
        if ($provincia < 1 || $provincia > 24) {
            return false;
        }

        $tercerDigito = (int) $cedula[2];
        if ($tercerDigito > 6) {
            return false;
        }

        // Algoritmo módulo 10
        $coeficientes = [2, 1, 2, 1, 2, 1, 2, 1, 2];
        $suma = 0;

        for ($i = 0; $i < 9; $i++) {
            $valor = (int) $cedula[$i] * $coeficientes[$i];
            if ($valor > 9) {
                $valor -= 9;
            }
            $suma += $valor;
        }

        $digitoVerificador = ($suma % 10 === 0) ? 0 : 10 - ($suma % 10);

        return $digitoVerificador === (int) $cedula[9];
    }

    /**
     * Generar username único
     */
    private function generarUsername(string $nombre, string $apellido): string
    {
        $base = strtolower(
            substr($nombre, 0, 1) .
            explode(' ', trim($apellido))[0]
        );

        $base = preg_replace('/[^a-z0-9]/', '', $base);
        $username = $base;
        $contador = 1;

        while (Usuario::where('usu_usuario', $username)->exists()) {
            $username = $base . $contador;
            $contador++;
        }

        return $username;
    }
}
