<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Api\ApiController;
use App\Models\SysRol;
use App\Models\SysPermiso;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;

class RolController extends ApiController
{
    /**
     * Listar roles
     * GET /api/v1/roles
     */
    public function index(Request $request): JsonResponse
    {
        return $this->ejecutar(function () use ($request) {

            $query = SysRol::withCount(['permisos' => function ($q) {
                $q->where('sys_permisos.estado', 1);
            }]);

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

            // Filtro por acceso
            if ($request->filled('acceso_web')) {
                $query->where('acceso_web', $request->acceso_web);
            }
            if ($request->filled('acceso_app')) {
                $query->where('acceso_app', $request->acceso_app);
            }

            $roles = $query->orderBy('rol_nombre', 'asc')->get();

            // Contar usuarios por rol
            $roles->each(function ($rol) {
                $rol->cantidad_usuarios = DB::table('usuarios')
                    ->join('perfil', 'usuarios.per_id', '=', 'perfil.per_id')
                    ->where('perfil.per_nombre', $rol->rol_codigo)
                    ->where('usuarios.usu_estado', 1)
                    ->count();
            });

            return $this->successResponse([
                'roles' => $roles->map(fn($rol) => [
                    'id' => $rol->rol_id,
                    'codigo' => $rol->rol_codigo,
                    'nombre' => $rol->rol_nombre,
                    'descripcion' => $rol->rol_descripcion,
                    'acceso_web' => (bool) $rol->acceso_web,
                    'acceso_app' => (bool) $rol->acceso_app,
                    'es_sistema' => (bool) $rol->es_sistema,
                    'estado' => $rol->estado,
                    'cantidad_permisos' => $rol->permisos_count,
                    'cantidad_usuarios' => $rol->cantidad_usuarios,
                ]),
            ]);

        }, 'Error listando roles');
    }

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

            $rol = SysRol::with(['permisos' => function ($q) {
                $q->where('sys_permisos.estado', 1)
                    ->orderBy('modulo')
                    ->orderBy('permiso_nombre');
            }])->findOrFail($id);

            // Agrupar permisos por módulo
            $permisosAgrupados = $rol->permisos->groupBy('modulo')->map(function ($permisos, $modulo) {
                return [
                    'modulo' => $modulo,
                    'permisos' => $permisos->map(fn($p) => [
                        'id' => $p->permiso_id,
                        'codigo' => $p->permiso_codigo,
                        'nombre' => $p->permiso_nombre,
                        'descripcion' => $p->permiso_descripcion,
                    ])->values(),
                ];
            })->values();

            // Usuarios con este rol
            $usuarios = DB::table('usuarios')
                ->join('perfil', 'usuarios.per_id', '=', 'perfil.per_id')
                ->where('perfil.per_nombre', $rol->rol_codigo)
                ->where('usuarios.usu_estado', 1)
                ->select('usuarios.usu_id', 'usuarios.usu_nombre', 'usuarios.usu_apellido', 'usuarios.usu_email')
                ->limit(10)
                ->get();

            return $this->successResponse([
                'rol' => [
                    'id' => $rol->rol_id,
                    'codigo' => $rol->rol_codigo,
                    'nombre' => $rol->rol_nombre,
                    'descripcion' => $rol->rol_descripcion,
                    'acceso_web' => (bool) $rol->acceso_web,
                    'acceso_app' => (bool) $rol->acceso_app,
                    'es_sistema' => (bool) $rol->es_sistema,
                    'estado' => $rol->estado,
                ],
                'permisos_agrupados' => $permisosAgrupados,
                'usuarios' => $usuarios->map(fn($u) => [
                    'id' => $u->usu_id,
                    'nombre_completo' => "{$u->usu_nombre} {$u->usu_apellido}",
                    'email' => $u->usu_email,
                ]),
                'total_usuarios' => DB::table('usuarios')
                    ->join('perfil', 'usuarios.per_id', '=', 'perfil.per_id')
                    ->where('perfil.per_nombre', $rol->rol_codigo)
                    ->where('usuarios.usu_estado', 1)
                    ->count(),
            ]);

        }, 'Error obteniendo rol');
    }

    /**
     * Listar todos los permisos disponibles (agrupados por módulo)
     * GET /api/v1/roles/permisos
     */
    public function permisos(): JsonResponse
    {
        return $this->ejecutar(function () {

            $permisos = SysPermiso::activos()
                ->orderBy('modulo')
                ->orderBy('permiso_nombre')
                ->get();

            $agrupados = $permisos->groupBy('modulo')->map(function ($permisos, $modulo) {
                return [
                    'modulo' => $modulo,
                    'permisos' => $permisos->map(fn($p) => [
                        'id' => $p->permiso_id,
                        'codigo' => $p->permiso_codigo,
                        'nombre' => $p->permiso_nombre,
                        'descripcion' => $p->permiso_descripcion,
                    ])->values(),
                ];
            })->values();

            return $this->successResponse([
                'modulos' => $agrupados,
                'total_permisos' => $permisos->count(),
            ]);

        }, 'Error listando permisos');
    }

    /**
     * Actualizar permisos de un rol
     * PUT /api/v1/roles/{id}/permisos
     */
    public function updatePermisos(Request $request, int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($request, $id) {

            $rol = SysRol::findOrFail($id);

            // No permitir modificar roles de sistema
            if ($rol->esRolSistema() && $rol->rol_codigo === 'SISTEMAS') {
                return $this->forbiddenResponse(
                    'No se pueden modificar los permisos del rol SISTEMAS'
                );
            }

            $request->validate([
                'permisos' => 'required|array',
                'permisos.*' => 'integer|exists:sys_permisos,permiso_id',
            ], [
                'permisos.required' => 'Debe enviar la lista de permisos',
                'permisos.array' => 'Los permisos deben ser un arreglo',
            ]);

            $permisosAnteriores = $rol->permisos()->pluck('sys_permisos.permiso_id')->toArray();

            DB::beginTransaction();
            try {
                // Sincronizar permisos con pivot data
                $syncData = [];
                foreach ($request->permisos as $permisoId) {
                    $syncData[$permisoId] = [
                        'fecha_asignacion' => now(),
                        'usuario_asigna' => $this->usuarioId(),
                    ];
                }

                $rol->permisos()->sync($syncData);

                DB::commit();

                // Registrar auditoría
                $this->registrarAuditoria(
                    'ACTUALIZAR_PERMISOS',
                    'sys_roles',
                    $rol->rol_id,
                    ['permisos' => $permisosAnteriores],
                    ['permisos' => $request->permisos]
                );

                return $this->successResponse([
                    'rol_id' => $rol->rol_id,
                    'permisos_asignados' => count($request->permisos),
                ], 'Permisos actualizados exitosamente');

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

        }, 'Error actualizando permisos');
    }

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

            $request->validate([
                'codigo' => [
                    'required',
                    'string',
                    'max:20',
                    'alpha_dash',
                    Rule::unique('sys_roles', 'rol_codigo'),
                ],
                'nombre' => 'required|string|max:50',
                'descripcion' => 'nullable|string|max:255',
                'acceso_web' => 'required|boolean',
                'acceso_app' => 'required|boolean',
                'permisos' => 'nullable|array',
                'permisos.*' => 'integer|exists:sys_permisos,permiso_id',
            ]);

            DB::beginTransaction();
            try {
                $rol = SysRol::create([
                    'rol_codigo' => strtoupper($request->codigo),
                    'rol_nombre' => $request->nombre,
                    'rol_descripcion' => $request->descripcion,
                    'acceso_web' => $request->acceso_web,
                    'acceso_app' => $request->acceso_app,
                    'es_sistema' => false,
                    'estado' => 1,
                ]);

                // Asignar permisos si se envían
                if ($request->filled('permisos')) {
                    $syncData = [];
                    foreach ($request->permisos as $permisoId) {
                        $syncData[$permisoId] = [
                            'fecha_asignacion' => now(),
                            'usuario_asigna' => $this->usuarioId(),
                        ];
                    }
                    $rol->permisos()->sync($syncData);
                }

                DB::commit();

                // Registrar auditoría
                $this->registrarAuditoria('CREAR', 'sys_roles', $rol->rol_id, null, $rol->toArray());

                return $this->createdResponse([
                    'rol' => [
                        'id' => $rol->rol_id,
                        'codigo' => $rol->rol_codigo,
                        'nombre' => $rol->rol_nombre,
                    ],
                ], 'Rol creado exitosamente');

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

        }, 'Error creando rol');
    }

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

            $rol = SysRol::findOrFail($id);

            // No permitir modificar roles de sistema base
            if ($rol->esRolSistema()) {
                return $this->forbiddenResponse(
                    'No se puede modificar un rol de sistema'
                );
            }

            $request->validate([
                'nombre' => 'sometimes|required|string|max:50',
                'descripcion' => 'nullable|string|max:255',
                'acceso_web' => 'sometimes|required|boolean',
                'acceso_app' => 'sometimes|required|boolean',
            ]);

            $datosAnteriores = $rol->toArray();

            $rol->update([
                'rol_nombre' => $request->input('nombre', $rol->rol_nombre),
                'rol_descripcion' => $request->input('descripcion', $rol->rol_descripcion),
                'acceso_web' => $request->input('acceso_web', $rol->acceso_web),
                'acceso_app' => $request->input('acceso_app', $rol->acceso_app),
            ]);

            // Registrar auditoría
            $this->registrarAuditoria('ACTUALIZAR', 'sys_roles', $rol->rol_id, $datosAnteriores, $rol->toArray());

            return $this->successResponse([
                'rol' => [
                    'id' => $rol->rol_id,
                    'codigo' => $rol->rol_codigo,
                    'nombre' => $rol->rol_nombre,
                ],
            ], 'Rol actualizado exitosamente');

        }, 'Error actualizando rol');
    }

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

            $rol = SysRol::findOrFail($id);

            // No permitir desactivar roles de sistema
            if ($rol->esRolSistema()) {
                return $this->forbiddenResponse(
                    'No se puede desactivar un rol de sistema'
                );
            }

            $estadoAnterior = $rol->estado;
            $rol->estado = $rol->estado == 1 ? 0 : 1;
            $rol->save();

            // Registrar auditoría
            $this->registrarAuditoria(
                $rol->estado == 1 ? 'ACTIVAR' : 'DESACTIVAR',
                'sys_roles',
                $rol->rol_id,
                ['estado' => $estadoAnterior],
                ['estado' => $rol->estado]
            );

            $mensaje = $rol->estado == 1
                ? 'Rol activado exitosamente'
                : 'Rol desactivado exitosamente';

            return $this->successResponse([
                'id' => $rol->rol_id,
                'estado' => $rol->estado,
            ], $mensaje);

        }, 'Error cambiando estado del rol');
    }
}
