<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Api\ApiController;
use App\Models\MantProgramacion;
use App\Models\MantAprobacion;
use App\Models\JefeOperativoPeaje;
use App\Models\Usuario;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use OpenApi\Attributes as OA;

#[OA\Schema(
    schema: "Aprobacion",
    properties: [
        new OA\Property(property: "aprobacion_id", type: "integer", example: 1),
        new OA\Property(property: "prog_id", type: "integer", example: 100),
        new OA\Property(property: "tipo", type: "string", enum: ["APROBADO", "RECHAZADO"]),
        new OA\Property(property: "fecha", type: "string", format: "date-time"),
        new OA\Property(property: "pin_validado", type: "boolean"),
        new OA\Property(property: "observaciones", type: "string", nullable: true),
        new OA\Property(property: "motivo_rechazo", type: "string", nullable: true),
        new OA\Property(property: "gps", type: "object", nullable: true, properties: [
            new OA\Property(property: "latitud", type: "number", format: "float"),
            new OA\Property(property: "longitud", type: "number", format: "float")
        ])
    ]
)]
#[OA\Schema(
    schema: "AprobarMantenimientoRequest",
    required: ["qr_code", "pin"],
    properties: [
        new OA\Property(property: "qr_code", type: "string", description: "Código QR escaneado del técnico"),
        new OA\Property(property: "pin", type: "string", minLength: 6, maxLength: 6, description: "PIN de 6 dígitos del Jefe Operativo"),
        new OA\Property(property: "latitud", type: "number", format: "float", minimum: -90, maximum: 90),
        new OA\Property(property: "longitud", type: "number", format: "float", minimum: -180, maximum: 180),
        new OA\Property(property: "observaciones", type: "string", maxLength: 500)
    ]
)]
#[OA\Schema(
    schema: "RechazarMantenimientoRequest",
    required: ["motivo"],
    properties: [
        new OA\Property(property: "motivo", type: "string", minLength: 10, maxLength: 500, description: "Motivo del rechazo (mínimo 10 caracteres)"),
        new OA\Property(property: "latitud", type: "number", format: "float"),
        new OA\Property(property: "longitud", type: "number", format: "float")
    ]
)]
#[OA\Schema(
    schema: "AsignarJefeRequest",
    required: ["jefe_id", "peaje_id", "pin"],
    properties: [
        new OA\Property(property: "jefe_id", type: "integer", description: "ID del usuario con perfil JEFE_OPERATIVO"),
        new OA\Property(property: "peaje_id", type: "integer", description: "ID del centro/peaje"),
        new OA\Property(property: "pin", type: "string", minLength: 6, maxLength: 6, pattern: "^[0-9]+$", description: "PIN numérico de 6 dígitos")
    ]
)]
class AprobacionController extends ApiController
{
    /**
     * Listar mantenimientos pendientes de aprobación
     * GET /api/v1/aprobaciones/pendientes
     */
    #[OA\Get(
        path: "/api/v1/aprobaciones/pendientes",
        summary: "Listar mantenimientos pendientes de aprobación",
        description: "Obtiene todos los mantenimientos en estado PEND_APROBACION. Los Jefes Operativos solo ven los de sus peajes asignados",
        tags: ["Aprobaciones"],
        security: [["sanctum" => []]],
        parameters: [
            new OA\Parameter(name: "peaje_id", in: "query", required: false, schema: new OA\Schema(type: "integer")),
            new OA\Parameter(name: "concesion_id", in: "query", required: false, schema: new OA\Schema(type: "integer"))
        ],
        responses: [
            new OA\Response(
                response: 200,
                description: "Lista de pendientes de aprobación",
                content: new OA\JsonContent(properties: [
                    new OA\Property(property: "success", type: "boolean", example: true),
                    new OA\Property(property: "data", type: "object", properties: [
                        new OA\Property(property: "total", type: "integer"),
                        new OA\Property(property: "pendientes", type: "array", items: new OA\Items(
                            properties: [
                                new OA\Property(property: "prog_id", type: "integer"),
                                new OA\Property(property: "fecha_programada", type: "string", format: "date"),
                                new OA\Property(property: "qr_code", type: "string"),
                                new OA\Property(property: "qr_expira", type: "string", format: "date-time"),
                                new OA\Property(property: "qr_vigente", type: "boolean"),
                                new OA\Property(property: "minutos_esperando", type: "integer"),
                                new OA\Property(property: "tecnico", type: "object"),
                                new OA\Property(property: "peaje", type: "object"),
                                new OA\Property(property: "total_evidencias", type: "integer")
                            ]
                        ))
                    ])
                ])
            )
        ]
    )]
    public function pendientes(Request $request): JsonResponse
    {
        return $this->ejecutar(function () use ($request) {

            $request->validate([
                'peaje_id' => 'nullable|integer',
                'concesion_id' => 'nullable|integer',
            ]);

            $usuario = $this->usuarioActual();

            $query = MantProgramacion::with([
                'estadoMantenimiento',
                'tecnico:usu_id,usu_nombre,usu_apellido',
                'centro:id_centro,nombre_centro,id_concesion',
                'centro.concesion:id_concesion,nombre',
                'evidencias' => fn($q) => $q->activas(),
            ])
            ->whereHas('estadoMantenimiento', function ($q) {
                $q->where('estado_codigo', 'PEND_APROBACION');
            })
            ->activos();

            // Filtrar por peajes asignados al Jefe Operativo
            $esJefeOperativo = $usuario->perfil &&
                $usuario->perfil->per_nombre === 'JEFE_OPERATIVO';

            if ($esJefeOperativo) {
                $peajesAsignados = JefeOperativoPeaje::where('jefe_id', $usuario->usu_id)
                    ->activos()
                    ->pluck('id_centro');

                $query->whereIn('id_centro', $peajesAsignados);
            }

            // Filtros adicionales
            if ($request->filled('peaje_id')) {
                $query->where('id_centro', $request->peaje_id);
            }

            if ($request->filled('concesion_id')) {
                $query->whereHas('centro', function ($q) use ($request) {
                    $q->where('id_concesion', $request->concesion_id);
                });
            }

            $pendientes = $query->orderBy('fecha_modifica', 'asc')->get();

            return $this->successResponse([
                'total' => $pendientes->count(),
                'pendientes' => $pendientes->map(fn($m) => [
                    'prog_id' => $m->prog_id,
                    'fecha_programada' => $m->fecha_programada,
                    'qr_code' => $m->qr_code,
                    'qr_expira' => $m->qr_expira,
                    'qr_vigente' => $m->qrEstaVigente(),
                    'minutos_esperando' => $m->fecha_modifica
                        ? now()->diffInMinutes($m->fecha_modifica)
                        : null,
                    'tecnico' => $m->tecnico ? [
                        'id' => $m->tecnico->usu_id,
                        'nombre' => $m->tecnico->nombre_completo,
                    ] : null,
                    'peaje' => [
                        'id' => $m->centro->id_centro,
                        'nombre' => $m->centro->nombre_centro,
                        'concesion' => $m->centro->concesion->nombre,
                    ],
                    'total_evidencias' => $m->evidencias->count(),
                ]),
            ]);

        }, 'Error obteniendo pendientes de aprobación');
    }

    /**
     * Aprobar mantenimiento con QR + PIN
     * POST /api/v1/aprobaciones/{progId}/aprobar
     *
     * Usa el SP: sp_aprobar_mantenimiento_qr
     */
    #[OA\Post(
        path: "/api/v1/aprobaciones/{progId}/aprobar",
        summary: "Aprobar mantenimiento con QR + PIN",
        description: "Aprueba un mantenimiento validando el código QR del técnico y el PIN del Jefe Operativo. Usa el SP sp_aprobar_mantenimiento_qr",
        tags: ["Aprobaciones"],
        security: [["sanctum" => []]],
        parameters: [
            new OA\Parameter(name: "progId", in: "path", required: true, schema: new OA\Schema(type: "integer"))
        ],
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(ref: "#/components/schemas/AprobarMantenimientoRequest")
        ),
        responses: [
            new OA\Response(
                response: 200,
                description: "Mantenimiento aprobado exitosamente",
                content: new OA\JsonContent(properties: [
                    new OA\Property(property: "success", type: "boolean", example: true),
                    new OA\Property(property: "message", type: "string"),
                    new OA\Property(property: "data", type: "object", properties: [
                        new OA\Property(property: "prog_id", type: "integer"),
                        new OA\Property(property: "tipo", type: "string", example: "APROBADO")
                    ])
                ])
            ),
            new OA\Response(
                response: 400,
                description: "Error de validación QR/PIN",
                content: new OA\JsonContent(properties: [
                    new OA\Property(property: "success", type: "boolean", example: false),
                    new OA\Property(property: "message", type: "string"),
                    new OA\Property(property: "data", type: "object", properties: [
                        new OA\Property(property: "code", type: "string", enum: ["QR_INVALIDO", "QR_EXPIRADO", "PIN_INCORRECTO", "PIN_BLOQUEADO", "NO_AUTORIZADO", "ESTADO_INVALIDO"])
                    ])
                ])
            )
        ]
    )]
    public function aprobar(Request $request, int $progId): JsonResponse
    {
        return $this->ejecutar(function () use ($request, $progId) {

            $request->validate([
                'qr_code' => 'required|string',
                'pin' => 'required|string|size:6',
                'latitud' => 'nullable|numeric|between:-90,90',
                'longitud' => 'nullable|numeric|between:-180,180',
                'observaciones' => 'nullable|string|max:500',
            ]);

            // Llamar al Stored Procedure
            $resultado = $this->ejecutarSP('sp_aprobar_mantenimiento_qr', [
                $progId,                    // p_prog_id
                $request->qr_code,          // p_qr_code
                $request->pin,              // p_pin
                $request->latitud,          // p_latitud
                $request->longitud,         // p_longitud
                $this->usuarioId(),         // p_usuario_id
            ]);

            $respuesta = $this->parsearRespuestaSP($resultado);

            if (!($respuesta['success'] ?? false)) {
                $codigo = $respuesta['code'] ?? 'ERROR';

                // Mensajes específicos según el código
                $mensaje = match($codigo) {
                    'QR_INVALIDO' => 'El código QR no es válido para este mantenimiento',
                    'QR_EXPIRADO' => 'El código QR ha expirado. Solicite al técnico que genere uno nuevo',
                    'PIN_INCORRECTO' => 'PIN incorrecto. ' . ($respuesta['data']['intentos'] ?? 0) . ' intentos restantes',
                    'PIN_BLOQUEADO' => 'PIN bloqueado temporalmente. Intente en 15 minutos',
                    'NO_AUTORIZADO' => 'No tiene autorización para aprobar mantenimientos en este peaje',
                    'ESTADO_INVALIDO' => 'El mantenimiento no está pendiente de aprobación',
                    default => $respuesta['message'] ?? 'Error al aprobar mantenimiento',
                };

                return $this->errorResponse($mensaje, 400, ['code' => $codigo]);
            }

            // Si hay observaciones, guardarlas en la aprobación
            if ($request->filled('observaciones')) {
                MantAprobacion::where('prog_id', $progId)
                    ->orderBy('aprobacion_id', 'desc')
                    ->first()
                    ?->update(['observaciones' => $request->observaciones]);
            }

            $this->registrarAuditoria('APROBAR_MANTENIMIENTO', 'mant_aprobaciones', $progId, null, [
                'tipo' => 'APROBADO',
            ]);

            return $this->successResponse([
                'prog_id' => $progId,
                'tipo' => 'APROBADO',
            ], 'Mantenimiento aprobado exitosamente');

        }, 'Error aprobando mantenimiento');
    }

    /**
     * Rechazar mantenimiento
     * POST /api/v1/aprobaciones/{progId}/rechazar
     */
    #[OA\Post(
        path: "/api/v1/aprobaciones/{progId}/rechazar",
        summary: "Rechazar mantenimiento",
        description: "Rechaza un mantenimiento indicando el motivo. Solo Jefes Operativos del peaje o usuarios SISTEMAS/ADMINISTRACION",
        tags: ["Aprobaciones"],
        security: [["sanctum" => []]],
        parameters: [
            new OA\Parameter(name: "progId", in: "path", required: true, schema: new OA\Schema(type: "integer"))
        ],
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(ref: "#/components/schemas/RechazarMantenimientoRequest")
        ),
        responses: [
            new OA\Response(
                response: 200,
                description: "Mantenimiento rechazado",
                content: new OA\JsonContent(properties: [
                    new OA\Property(property: "success", type: "boolean", example: true),
                    new OA\Property(property: "message", type: "string"),
                    new OA\Property(property: "data", type: "object", properties: [
                        new OA\Property(property: "prog_id", type: "integer"),
                        new OA\Property(property: "tipo", type: "string", example: "RECHAZADO")
                    ])
                ])
            ),
            new OA\Response(response: 400, description: "Estado no válido para rechazar"),
            new OA\Response(response: 403, description: "No autorizado para rechazar en este peaje"),
            new OA\Response(response: 404, description: "Mantenimiento no encontrado")
        ]
    )]
    public function rechazar(Request $request, int $progId): JsonResponse
    {
        return $this->ejecutar(function () use ($request, $progId) {

            $request->validate([
                'motivo' => 'required|string|min:10|max:500',
                'latitud' => 'nullable|numeric|between:-90,90',
                'longitud' => 'nullable|numeric|between:-180,180',
            ]);

            $mantenimiento = MantProgramacion::with('estadoMantenimiento')
                ->where('prog_id', $progId)
                ->activos()
                ->first();

            if (!$mantenimiento) {
                return $this->notFoundResponse('Mantenimiento no encontrado');
            }

            if ($mantenimiento->estadoMantenimiento->estado_codigo !== 'PEND_APROBACION') {
                return $this->errorResponse(
                    'El mantenimiento no está pendiente de aprobación',
                    400
                );
            }

            // Verificar que el usuario es Jefe Operativo del peaje
            $usuario = $this->usuarioActual();
            $esAutorizado = JefeOperativoPeaje::where('jefe_id', $usuario->usu_id)
                ->where('id_centro', $mantenimiento->id_centro)
                ->activos()
                ->exists();

            // Permitir también a SISTEMAS y ADMINISTRACION
            $esAdmin = $usuario->perfil &&
                in_array($usuario->perfil->per_nombre, ['SISTEMAS', 'ADMINISTRACION']);

            if (!$esAutorizado && !$esAdmin) {
                return $this->forbiddenResponse('No tiene autorización para rechazar en este peaje');
            }

            DB::beginTransaction();
            try {
                // Obtener estado RECHAZADO
                $estadoRechazado = DB::table('mant_estados')
                    ->where('estado_codigo', 'RECHAZADO')
                    ->first();

                // Crear registro de aprobación (rechazo)
                MantAprobacion::create([
                    'prog_id' => $progId,
                    'jefe_operativo_id' => $usuario->usu_id,
                    'tipo' => MantAprobacion::TIPO_RECHAZADO,
                    'qr_escaneado' => $mantenimiento->qr_code ?? '',
                    'pin_validado' => false,
                    'latitud' => $request->latitud,
                    'longitud' => $request->longitud,
                    'motivo_rechazo' => $request->motivo,
                ]);

                // Actualizar estado del mantenimiento
                $mantenimiento->update([
                    'estado_id' => $estadoRechazado->estado_id,
                    'qr_code' => null,
                    'qr_expira' => null,
                    'usuario_modifica' => $usuario->usu_id,
                ]);

                // Registrar en historial
                DB::table('mant_estado_historial')->insert([
                    'prog_id' => $progId,
                    'estado_anterior_id' => $mantenimiento->getOriginal('estado_id'),
                    'estado_nuevo_id' => $estadoRechazado->estado_id,
                    'latitud' => $request->latitud,
                    'longitud' => $request->longitud,
                    'observaciones' => "Rechazado: {$request->motivo}",
                    'usuario_ejecuta' => $usuario->usu_id,
                    'fecha_cambio' => now(),
                ]);

                DB::commit();

                $this->registrarAuditoria('RECHAZAR_MANTENIMIENTO', 'mant_aprobaciones', $progId, null, [
                    'tipo' => 'RECHAZADO',
                    'motivo' => $request->motivo,
                ]);

                // TODO: Enviar notificación push al técnico

                return $this->successResponse([
                    'prog_id' => $progId,
                    'tipo' => 'RECHAZADO',
                ], 'Mantenimiento rechazado');

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

        }, 'Error rechazando mantenimiento');
    }

    /**
     * Historial de aprobaciones
     * GET /api/v1/aprobaciones/historial
     */
    #[OA\Get(
        path: "/api/v1/aprobaciones/historial",
        summary: "Historial de aprobaciones",
        description: "Obtiene el historial de aprobaciones y rechazos con filtros. Jefes Operativos solo ven sus propias aprobaciones",
        tags: ["Aprobaciones"],
        security: [["sanctum" => []]],
        parameters: [
            new OA\Parameter(name: "fecha_desde", in: "query", required: false, schema: new OA\Schema(type: "string", format: "date")),
            new OA\Parameter(name: "fecha_hasta", in: "query", required: false, schema: new OA\Schema(type: "string", format: "date")),
            new OA\Parameter(name: "tipo", in: "query", required: false, schema: new OA\Schema(type: "string", enum: ["APROBADO", "RECHAZADO"])),
            new OA\Parameter(name: "peaje_id", in: "query", required: false, schema: new OA\Schema(type: "integer")),
            new OA\Parameter(name: "per_page", in: "query", required: false, schema: new OA\Schema(type: "integer", minimum: 5, maximum: 100, default: 20))
        ],
        responses: [
            new OA\Response(
                response: 200,
                description: "Historial de aprobaciones",
                content: new OA\JsonContent(properties: [
                    new OA\Property(property: "success", type: "boolean", example: true),
                    new OA\Property(property: "data", type: "object", properties: [
                        new OA\Property(property: "historial", type: "array", items: new OA\Items(ref: "#/components/schemas/Aprobacion")),
                        new OA\Property(property: "pagination", type: "object")
                    ])
                ])
            )
        ]
    )]
    public function historial(Request $request): JsonResponse
    {
        return $this->ejecutar(function () use ($request) {

            $request->validate([
                'fecha_desde' => 'nullable|date',
                'fecha_hasta' => 'nullable|date|after_or_equal:fecha_desde',
                'tipo' => 'nullable|string|in:APROBADO,RECHAZADO',
                'peaje_id' => 'nullable|integer',
                'per_page' => 'nullable|integer|min:5|max:100',
            ]);

            $query = MantAprobacion::with([
                'programacion:prog_id,fecha_programada,id_centro,tecnico_asignado',
                'programacion.centro:id_centro,nombre_centro',
                'programacion.tecnico:usu_id,usu_nombre,usu_apellido',
                'jefeOperativo:usu_id,usu_nombre,usu_apellido',
            ]);

            if ($request->filled('fecha_desde')) {
                $query->whereDate('fecha_aprobacion', '>=', $request->fecha_desde);
            }

            if ($request->filled('fecha_hasta')) {
                $query->whereDate('fecha_aprobacion', '<=', $request->fecha_hasta);
            }

            if ($request->filled('tipo')) {
                $query->where('tipo', $request->tipo);
            }

            if ($request->filled('peaje_id')) {
                $query->whereHas('programacion', function ($q) use ($request) {
                    $q->where('id_centro', $request->peaje_id);
                });
            }

            // Si es Jefe Operativo, solo ver sus aprobaciones
            $usuario = $this->usuarioActual();
            if ($usuario->perfil && $usuario->perfil->per_nombre === 'JEFE_OPERATIVO') {
                $query->where('jefe_operativo_id', $usuario->usu_id);
            }

            $historial = $query
                ->orderBy('fecha_aprobacion', 'desc')
                ->paginate($request->get('per_page', 20));

            return $this->successResponse([
                'historial' => collect($historial->items())->map(fn($a) => [
                    'aprobacion_id' => $a->aprobacion_id,
                    'prog_id' => $a->prog_id,
                    'tipo' => $a->tipo,
                    'fecha' => $a->fecha_aprobacion,
                    'peaje' => $a->programacion?->centro?->nombre_centro,
                    'tecnico' => $a->programacion?->tecnico?->nombre_completo,
                    'jefe' => $a->jefeOperativo?->nombre_completo,
                    'observaciones' => $a->observaciones,
                    'motivo_rechazo' => $a->motivo_rechazo,
                ]),
                'pagination' => [
                    'current_page' => $historial->currentPage(),
                    'per_page' => $historial->perPage(),
                    'total' => $historial->total(),
                    'last_page' => $historial->lastPage(),
                ],
            ]);

        }, 'Error obteniendo historial de aprobaciones');
    }

    /**
     * Ver detalle de una aprobación
     * GET /api/v1/aprobaciones/{id}
     */
    #[OA\Get(
        path: "/api/v1/aprobaciones/{id}",
        summary: "Ver detalle de aprobación",
        description: "Obtiene el detalle completo de una aprobación incluyendo mantenimiento, técnico y evidencias",
        tags: ["Aprobaciones"],
        security: [["sanctum" => []]],
        parameters: [
            new OA\Parameter(name: "id", in: "path", required: true, schema: new OA\Schema(type: "integer"))
        ],
        responses: [
            new OA\Response(
                response: 200,
                description: "Detalle de aprobación",
                content: new OA\JsonContent(properties: [
                    new OA\Property(property: "success", type: "boolean", example: true),
                    new OA\Property(property: "data", type: "object", properties: [
                        new OA\Property(property: "aprobacion", ref: "#/components/schemas/Aprobacion"),
                        new OA\Property(property: "mantenimiento", type: "object"),
                        new OA\Property(property: "tecnico", type: "object"),
                        new OA\Property(property: "jefe_operativo", type: "object"),
                        new OA\Property(property: "evidencias", type: "integer")
                    ])
                ])
            ),
            new OA\Response(response: 404, description: "Aprobación no encontrada")
        ]
    )]
    public function show(int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($id) {

            $aprobacion = MantAprobacion::with([
                'programacion.estadoMantenimiento',
                'programacion.centro.concesion',
                'programacion.tecnico',
                'programacion.evidencias' => fn($q) => $q->activas(),
                'jefeOperativo',
            ])
            ->where('aprobacion_id', $id)
            ->first();

            if (!$aprobacion) {
                return $this->notFoundResponse('Aprobación no encontrada');
            }

            return $this->successResponse([
                'aprobacion' => [
                    'aprobacion_id' => $aprobacion->aprobacion_id,
                    'tipo' => $aprobacion->tipo,
                    'fecha' => $aprobacion->fecha_aprobacion,
                    'pin_validado' => $aprobacion->pin_validado,
                    'observaciones' => $aprobacion->observaciones,
                    'motivo_rechazo' => $aprobacion->motivo_rechazo,
                    'gps' => $aprobacion->tieneGps() ? [
                        'latitud' => $aprobacion->latitud,
                        'longitud' => $aprobacion->longitud,
                    ] : null,
                ],
                'mantenimiento' => [
                    'prog_id' => $aprobacion->programacion->prog_id,
                    'fecha' => $aprobacion->programacion->fecha_programada,
                    'estado' => $aprobacion->programacion->estadoMantenimiento->estado_nombre,
                    'peaje' => $aprobacion->programacion->centro->nombre_centro,
                    'concesion' => $aprobacion->programacion->centro->concesion->nombre,
                ],
                'tecnico' => $aprobacion->programacion->tecnico ? [
                    'id' => $aprobacion->programacion->tecnico->usu_id,
                    'nombre' => $aprobacion->programacion->tecnico->nombre_completo,
                ] : null,
                'jefe_operativo' => $aprobacion->jefeOperativo ? [
                    'id' => $aprobacion->jefeOperativo->usu_id,
                    'nombre' => $aprobacion->jefeOperativo->nombre_completo,
                ] : null,
                'evidencias' => $aprobacion->programacion->evidencias->count(),
            ]);

        }, 'Error obteniendo detalle de aprobación');
    }

    // ============================================================
    // GESTIÓN DE JEFES OPERATIVOS
    // ============================================================

    /**
     * Listar jefes operativos y sus asignaciones
     * GET /api/v1/aprobaciones/jefes
     */
    #[OA\Get(
        path: "/api/v1/aprobaciones/jefes",
        summary: "Listar jefes operativos y asignaciones",
        description: "Obtiene todas las asignaciones de Jefes Operativos a peajes",
        tags: ["Jefes Operativos"],
        security: [["sanctum" => []]],
        parameters: [
            new OA\Parameter(name: "peaje_id", in: "query", required: false, schema: new OA\Schema(type: "integer"))
        ],
        responses: [
            new OA\Response(
                response: 200,
                description: "Lista de asignaciones",
                content: new OA\JsonContent(properties: [
                    new OA\Property(property: "success", type: "boolean", example: true),
                    new OA\Property(property: "data", type: "object", properties: [
                        new OA\Property(property: "total", type: "integer"),
                        new OA\Property(property: "asignaciones", type: "array", items: new OA\Items(
                            properties: [
                                new OA\Property(property: "asignacion_id", type: "integer"),
                                new OA\Property(property: "jefe", type: "object"),
                                new OA\Property(property: "peaje", type: "object"),
                                new OA\Property(property: "tiene_pin", type: "boolean"),
                                new OA\Property(property: "pin_bloqueado", type: "boolean"),
                                new OA\Property(property: "fecha_asignacion", type: "string", format: "date-time")
                            ]
                        ))
                    ])
                ])
            )
        ]
    )]
    public function listarJefes(Request $request): JsonResponse
    {
        return $this->ejecutar(function () use ($request) {

            $request->validate([
                'peaje_id' => 'nullable|integer',
            ]);

            $query = JefeOperativoPeaje::with([
                'jefe:usu_id,usu_nombre,usu_apellido,usu_cedula,usu_email',
                'centro:id_centro,nombre_centro,id_concesion',
                'centro.concesion:id_concesion,nombre',
            ])
            ->activos();

            if ($request->filled('peaje_id')) {
                $query->where('id_centro', $request->peaje_id);
            }

            $asignaciones = $query->orderBy('fecha_asigna', 'desc')->get();

            return $this->successResponse([
                'total' => $asignaciones->count(),
                'asignaciones' => $asignaciones->map(fn($a) => [
                    'asignacion_id' => $a->asignacion_id,
                    'jefe' => $a->jefe ? [
                        'id' => $a->jefe->usu_id,
                        'nombre' => $a->jefe->nombre_completo,
                        'cedula' => $a->jefe->usu_cedula,
                        'email' => $a->jefe->usu_email,
                    ] : null,
                    'peaje' => [
                        'id' => $a->centro->id_centro,
                        'nombre' => $a->centro->nombre_centro,
                        'concesion' => $a->centro->concesion->nombre,
                    ],
                    'tiene_pin' => !empty($a->pin_hash),
                    'pin_bloqueado' => $a->estaBloqueado(),
                    'fecha_asignacion' => $a->fecha_asigna,
                ]),
            ]);

        }, 'Error obteniendo jefes operativos');
    }

    /**
     * Asignar jefe operativo a peaje
     * POST /api/v1/aprobaciones/jefes
     */
    #[OA\Post(
        path: "/api/v1/aprobaciones/jefes",
        summary: "Asignar jefe operativo a peaje",
        description: "Asigna un usuario con perfil JEFE_OPERATIVO a un peaje y configura su PIN",
        tags: ["Jefes Operativos"],
        security: [["sanctum" => []]],
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(ref: "#/components/schemas/AsignarJefeRequest")
        ),
        responses: [
            new OA\Response(
                response: 201,
                description: "Jefe operativo asignado exitosamente",
                content: new OA\JsonContent(properties: [
                    new OA\Property(property: "success", type: "boolean", example: true),
                    new OA\Property(property: "message", type: "string"),
                    new OA\Property(property: "data", type: "object", properties: [
                        new OA\Property(property: "asignacion_id", type: "integer")
                    ])
                ])
            ),
            new OA\Response(response: 400, description: "Usuario ya asignado a este peaje"),
            new OA\Response(response: 422, description: "El usuario no tiene perfil JEFE_OPERATIVO")
        ]
    )]
    public function asignarJefe(Request $request): JsonResponse
    {
        return $this->ejecutar(function () use ($request) {

            $request->validate([
                'jefe_id' => 'required|integer|exists:usuarios,usu_id',
                'peaje_id' => 'required|integer|exists:peaje_centro,id_centro',
                'pin' => 'required|string|size:6|regex:/^[0-9]+$/',
            ]);

            // Verificar que el usuario tiene perfil JEFE_OPERATIVO
            $jefe = Usuario::with('perfil')->find($request->jefe_id);
            if (!$jefe || $jefe->perfil->per_nombre !== 'JEFE_OPERATIVO') {
                return $this->validationErrorResponse(
                    ['jefe_id' => ['El usuario debe tener perfil de Jefe Operativo']],
                    'Validación fallida'
                );
            }

            // Verificar si ya existe asignación
            $existe = JefeOperativoPeaje::where('jefe_id', $request->jefe_id)
                ->where('id_centro', $request->peaje_id)
                ->first();

            if ($existe) {
                if ($existe->estado == 1) {
                    return $this->errorResponse(
                        'El jefe ya está asignado a este peaje',
                        400
                    );
                }
                // Reactivar asignación
                $existe->estado = 1;
                $existe->establecerPin($request->pin);
                $existe->usuario_modifica = $this->usuarioId();
                $existe->save();

                return $this->successResponse([
                    'asignacion_id' => $existe->asignacion_id,
                ], 'Asignación reactivada exitosamente');
            }

            // Crear nueva asignación
            $asignacion = new JefeOperativoPeaje();
            $asignacion->jefe_id = $request->jefe_id;
            $asignacion->id_centro = $request->peaje_id;
            $asignacion->usuario_asigna = $this->usuarioId();
            $asignacion->estado = 1;
            $asignacion->save();
            $asignacion->establecerPin($request->pin);

            $this->registrarAuditoria('ASIGNAR_JEFE', 'jefe_operativo_peajes', $asignacion->asignacion_id, null, [
                'jefe_id' => $request->jefe_id,
                'peaje_id' => $request->peaje_id,
            ]);

            return $this->createdResponse([
                'asignacion_id' => $asignacion->asignacion_id,
            ], 'Jefe operativo asignado exitosamente');

        }, 'Error asignando jefe operativo');
    }

    /**
     * Cambiar PIN de jefe operativo
     * PUT /api/v1/aprobaciones/jefes/{id}/pin
     */
    #[OA\Put(
        path: "/api/v1/aprobaciones/jefes/{id}/pin",
        summary: "Cambiar PIN de jefe operativo",
        description: "Actualiza el PIN de una asignación de Jefe Operativo",
        tags: ["Jefes Operativos"],
        security: [["sanctum" => []]],
        parameters: [
            new OA\Parameter(name: "id", in: "path", required: true, description: "ID de la asignación", schema: new OA\Schema(type: "integer"))
        ],
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(
                required: ["pin"],
                properties: [
                    new OA\Property(property: "pin", type: "string", minLength: 6, maxLength: 6, pattern: "^[0-9]+$")
                ]
            )
        ),
        responses: [
            new OA\Response(
                response: 200,
                description: "PIN actualizado exitosamente",
                content: new OA\JsonContent(properties: [
                    new OA\Property(property: "success", type: "boolean", example: true),
                    new OA\Property(property: "message", type: "string"),
                    new OA\Property(property: "data", type: "object", properties: [
                        new OA\Property(property: "asignacion_id", type: "integer")
                    ])
                ])
            ),
            new OA\Response(response: 404, description: "Asignación no encontrada")
        ]
    )]
    public function cambiarPin(Request $request, int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($request, $id) {

            $request->validate([
                'pin' => 'required|string|size:6|regex:/^[0-9]+$/',
            ]);

            $asignacion = JefeOperativoPeaje::where('asignacion_id', $id)
                ->activos()
                ->first();

            if (!$asignacion) {
                return $this->notFoundResponse('Asignación no encontrada');
            }

            $asignacion->establecerPin($request->pin);

            $this->registrarAuditoria('CAMBIAR_PIN', 'jefe_operativo_peajes', $id, null, null);

            return $this->successResponse([
                'asignacion_id' => $id,
            ], 'PIN actualizado exitosamente');

        }, 'Error cambiando PIN');
    }

    /**
     * Desasignar jefe operativo de peaje
     * DELETE /api/v1/aprobaciones/jefes/{id}
     */
    #[OA\Delete(
        path: "/api/v1/aprobaciones/jefes/{id}",
        summary: "Desasignar jefe operativo de peaje",
        description: "Elimina (soft delete) la asignación de un Jefe Operativo a un peaje",
        tags: ["Jefes Operativos"],
        security: [["sanctum" => []]],
        parameters: [
            new OA\Parameter(name: "id", in: "path", required: true, schema: new OA\Schema(type: "integer"))
        ],
        responses: [
            new OA\Response(
                response: 200,
                description: "Jefe operativo desasignado",
                content: new OA\JsonContent(properties: [
                    new OA\Property(property: "success", type: "boolean", example: true),
                    new OA\Property(property: "message", type: "string"),
                    new OA\Property(property: "data", type: "object", properties: [
                        new OA\Property(property: "asignacion_id", type: "integer")
                    ])
                ])
            ),
            new OA\Response(response: 404, description: "Asignación no encontrada")
        ]
    )]
    public function desasignarJefe(int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($id) {

            $asignacion = JefeOperativoPeaje::where('asignacion_id', $id)
                ->activos()
                ->first();

            if (!$asignacion) {
                return $this->notFoundResponse('Asignación no encontrada');
            }

            $asignacion->estado = 0;
            $asignacion->usuario_modifica = $this->usuarioId();
            $asignacion->save();

            $this->registrarAuditoria('DESASIGNAR_JEFE', 'jefe_operativo_peajes', $id, [
                'jefe_id' => $asignacion->jefe_id,
                'peaje_id' => $asignacion->id_centro,
            ], null);

            return $this->successResponse([
                'asignacion_id' => $id,
            ], 'Jefe operativo desasignado');

        }, 'Error desasignando jefe operativo');
    }
}
