<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Api\ApiController;
use App\Models\MantProgramacion;
use App\Models\MantEstado;
use App\Models\MantEstadoHistorial;
use App\Models\MantChecklistRespuesta;
use App\Models\MantEvidencia;
use App\Models\ItemRevisionMantenimiento;
use App\Models\HardwareInventario;
use App\Models\ViaSubcentro;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Carbon\Carbon;
use OpenApi\Attributes as OA;

#[OA\Schema(
    schema: "Mantenimiento",
    properties: [
        new OA\Property(property: "prog_id", type: "integer", example: 1),
        new OA\Property(property: "fecha_programada", type: "string", format: "date", example: "2024-01-15"),
        new OA\Property(property: "observaciones", type: "string", nullable: true),
        new OA\Property(property: "qr_code", type: "string", nullable: true),
        new OA\Property(property: "qr_expira", type: "string", format: "date-time", nullable: true),
        new OA\Property(property: "qr_vigente", type: "boolean"),
        new OA\Property(property: "estado", type: "object"),
        new OA\Property(property: "tecnico", type: "object"),
        new OA\Property(property: "peaje", type: "object")
    ]
)]
#[OA\Schema(
    schema: "EstadoMantenimiento",
    properties: [
        new OA\Property(property: "id", type: "integer", example: 1),
        new OA\Property(property: "codigo", type: "string", example: "EN_MANTENIMIENTO"),
        new OA\Property(property: "nombre", type: "string", example: "En Mantenimiento"),
        new OA\Property(property: "color", type: "string", example: "#FFC107"),
        new OA\Property(property: "requiere_gps", type: "boolean", example: true)
    ]
)]
#[OA\Schema(
    schema: "CambiarEstadoRequest",
    required: ["estado"],
    properties: [
        new OA\Property(property: "estado", type: "string", enum: ["CAMINO_PEAJE", "LLEGADA_PEAJE", "EN_MANTENIMIENTO", "MANT_FINALIZADO", "RETORNO_INICIADO", "COMPLETADO"], example: "EN_MANTENIMIENTO"),
        new OA\Property(property: "latitud", type: "number", format: "float", example: -0.1807),
        new OA\Property(property: "longitud", type: "number", format: "float", example: -78.4678),
        new OA\Property(property: "precision", type: "number", format: "float", example: 10.5),
        new OA\Property(property: "observaciones", type: "string", example: "Iniciando mantenimiento preventivo")
    ]
)]
#[OA\Schema(
    schema: "GuardarChecklistRequest",
    required: ["inventario_id", "via_id", "id_item", "estado_equipo_id"],
    properties: [
        new OA\Property(property: "inventario_id", type: "integer", example: 15, description: "ID del equipo en hardware_inventario"),
        new OA\Property(property: "via_id", type: "integer", example: 1, description: "ID de la vía donde está instalado el equipo"),
        new OA\Property(property: "id_item", type: "integer", example: 3, description: "ID del item de revisión"),
        new OA\Property(property: "estado_equipo_id", type: "integer", example: 1, description: "1=Operativo, 2=Falla, 3=Requiere Cambio"),
        new OA\Property(property: "valor_medicion", type: "string", nullable: true, example: "120V"),
        new OA\Property(property: "observacion", type: "string", nullable: true, example: "Funciona correctamente")
    ]
)]
class MantenimientoController extends ApiController
{
    /**
     * Obtiene el usu_id del usuario autenticado para filtrar mantenimientos
     * Compatible con modelo User (tabla users) que tiene campo usu_id vinculado
     */
    private function getTecnicoId(): ?int
    {
        $user = $this->usuarioActual();
        if (!$user) {
            return null;
        }

        // Si es modelo User (tabla users), usar el campo usu_id que vincula con usuarios
        if ($user instanceof \App\Models\User) {
            return $user->usu_id;
        }

        // Si es modelo Usuario (tabla usuarios), usar usu_id directamente
        if ($user instanceof \App\Models\Usuario) {
            return $user->usu_id;
        }

        return null;
    }

    /**
     * Obtiene el nombre del perfil del usuario autenticado
     */
    private function getNombrePerfil(): ?string
    {
        $user = $this->usuarioActual();
        if (!$user || !$user->perfil) {
            return null;
        }
        return $user->perfil->per_nombre;
    }

    /**
     * Mapea un mantenimiento a formato de respuesta API estándar
     * Uso: $this->mapMantenimiento($mantenimiento)
     */
    private function mapMantenimiento(MantProgramacion $m, bool $incluirDetalles = false): array
    {
        $data = [
            'prog_id' => $m->prog_id,
            'fecha_programada' => $m->fecha_programada?->format('Y-m-d'),
            'observaciones' => $m->observaciones,
            'estado' => $m->estadoMantenimiento ? [
                'id' => $m->estadoMantenimiento->estado_id,
                'codigo' => $m->estadoMantenimiento->estado_codigo,
                'nombre' => $m->estadoMantenimiento->estado_nombre,
                'color' => $m->estadoMantenimiento->color_hex,
                'requiere_gps' => (bool) $m->estadoMantenimiento->requiere_gps,
            ] : null,
            'peaje' => $m->centro ? [
                'id' => $m->centro->id_centro,
                'nombre' => $m->centro->nombre_centro,
                'concesion' => $m->centro->concesion?->nombre ?? 'Sin concesión',
                'latitud' => $m->centro->latitud,
                'longitud' => $m->centro->longitud,
                'total_vias' => $m->centro->vias()->activas()->count(),
            ] : null,
            'via' => $m->via ? [
                'id' => $m->via->via_id,
                'nombre' => $m->via->nombre,
            ] : null,
            'tecnico' => $m->tecnico ? [
                'id' => $m->tecnico->usu_id,
                'nombre' => $m->tecnico->nombre_completo,
                'cedula' => $m->tecnico->usu_cedula,
            ] : null,
        ];

        // Agregar detalles adicionales si se solicitan
        if ($incluirDetalles) {
            $data['qr_code'] = $m->qr_code;
            $data['qr_expira'] = $m->qr_expira;
            $data['qr_vigente'] = $m->qrEstaVigente();
            $data['motivo_cancelacion'] = $m->motivo_cancelacion;
            $data['motivo_reprogramacion'] = $m->motivo_reprogramacion;
        }

        return $data;
    }

    /**
     * Mapea una colección de mantenimientos
     */
    private function mapMantenimientos($mantenimientos, bool $incluirDetalles = false): array
    {
        return $mantenimientos->map(fn($m) => $this->mapMantenimiento($m, $incluirDetalles))->toArray();
    }

    #[OA\Get(
        path: "/api/v1/mantenimientos",
        summary: "Listar mantenimientos",
        description: "Lista mantenimientos asignados. Los técnicos solo ven sus mantenimientos asignados. Admins ven todos.",
        operationId: "listarMantenimientos",
        tags: ["Mantenimientos"],
        security: [["sanctum" => []]],
        parameters: [
            new OA\Parameter(name: "fecha", in: "query", description: "Filtrar por fecha (YYYY-MM-DD)", schema: new OA\Schema(type: "string", format: "date")),
            new OA\Parameter(name: "estado_id", in: "query", description: "Filtrar por ID de estado", schema: new OA\Schema(type: "integer")),
            new OA\Parameter(name: "tecnico_id", in: "query", description: "Filtrar por técnico", schema: new OA\Schema(type: "integer")),
            new OA\Parameter(name: "concesion_id", in: "query", description: "Filtrar por concesión", schema: new OA\Schema(type: "integer")),
            new OA\Parameter(name: "peaje_id", in: "query", description: "Filtrar por peaje", schema: new OA\Schema(type: "integer")),
            new OA\Parameter(name: "per_page", in: "query", description: "Registros por página (5-100)", schema: new OA\Schema(type: "integer", default: 20))
        ],
        responses: [
            new OA\Response(response: 200, description: "Lista de mantenimientos"),
            new OA\Response(response: 401, description: "No autenticado")
        ]
    )]
    public function index(Request $request): JsonResponse
    {
        return $this->ejecutar(function () use ($request) {
            $request->validate([
                'fecha' => 'nullable|date',
                'estado_id' => 'nullable|integer',
                'tecnico_id' => 'nullable|integer',
                'concesion_id' => 'nullable|integer',
                'peaje_id' => 'nullable|integer',
                'per_page' => 'nullable|integer|min:5|max:100',
            ]);

            $query = MantProgramacion::with([
                'estadoMantenimiento',
                'tecnico:usu_id,usu_nombre,usu_apellido,usu_cedula',
                'centro:id_centro,nombre_centro,id_concesion',
                'centro.concesion:id_concesion,nombre',
                'via:via_id,nombre',
            ])->activos();

            if ($request->filled('fecha')) {
                $fechaFiltro = $request->fecha;
                $query->where(function ($q) use ($fechaFiltro) {
                    // Mantenimientos que inician en esa fecha O que están en rango (inicio <= fecha <= fin)
                    $q->whereDate('fecha_programada', $fechaFiltro)
                        ->orWhere(function ($sub) use ($fechaFiltro) {
                            $sub->whereDate('fecha_programada', '<=', $fechaFiltro)
                                ->whereDate('fecha_fin', '>=', $fechaFiltro);
                        });
                });
            }
            if ($request->filled('estado_id')) {
                $query->where('estado_id', $request->estado_id);
            }
            if ($request->filled('tecnico_id')) {
                $query->where('tecnico_asignado', $request->tecnico_id);
            }
            if ($request->filled('concesion_id')) {
                $query->whereHas('centro', fn($q) => $q->where('id_concesion', $request->concesion_id));
            }
            if ($request->filled('peaje_id')) {
                $query->where('id_centro', $request->peaje_id);
            }

            // Filtrar por técnico si el usuario tiene perfil de técnico
            $nombrePerfil = $this->getNombrePerfil();
            if ($nombrePerfil && in_array($nombrePerfil, ['TECNICOS', 'TECNICO', 'Tecnico'])) {
                $tecnicoId = $this->getTecnicoId();
                if ($tecnicoId) {
                    $query->where('tecnico_asignado', $tecnicoId);
                }
            }

            $mantenimientos = $query->orderBy('fecha_programada', 'asc')->orderBy('estado_id', 'asc')
                ->paginate($request->get('per_page', 20));

            return $this->successResponse([
                'mantenimientos' => $this->mapMantenimientos(collect($mantenimientos->items())),
                'pagination' => [
                    'current_page' => $mantenimientos->currentPage(),
                    'per_page' => $mantenimientos->perPage(),
                    'total' => $mantenimientos->total(),
                    'last_page' => $mantenimientos->lastPage(),
                ],
            ]);
        }, 'Error obteniendo mantenimientos');
    }

    #[OA\Get(
        path: "/api/v1/mantenimientos/estados",
        summary: "Listar estados de mantenimiento",
        description: "Retorna todos los estados posibles del flujo de mantenimiento",
        operationId: "listarEstadosMantenimiento",
        tags: ["Mantenimientos"],
        security: [["sanctum" => []]],
        responses: [new OA\Response(response: 200, description: "Lista de estados")]
    )]
    public function getEstados(): JsonResponse
    {
        return $this->ejecutar(function () {
            $estados = MantEstado::where('estado', 1)->orderBy('orden')->get();

            return $this->successResponse([
                'estados' => $estados->map(fn($e) => [
                    'estado_id' => $e->estado_id,
                    'codigo' => $e->estado_codigo,
                    'nombre' => $e->estado_nombre,
                    'descripcion' => $e->estado_descripcion,
                    'color' => $e->color_hex,
                    'requiere_gps' => (bool) $e->requiere_gps,
                    'orden' => $e->orden,
                ]),
            ]);
        }, 'Error obteniendo estados');
    }

    #[OA\Get(
        path: "/api/v1/mantenimientos/hoy",
        summary: "Mantenimientos del día para el técnico",
        description: "Retorna los mantenimientos programados para hoy del técnico autenticado",
        operationId: "mantenimientosHoy",
        tags: ["Mantenimientos"],
        security: [["sanctum" => []]],
        responses: [new OA\Response(response: 200, description: "Mantenimientos del día")]
    )]
    public function hoy(): JsonResponse
    {
        return $this->ejecutar(function () {
            $usuario = $this->usuarioActual();
            $tecnicoId = $this->getTecnicoId();

            if (!$tecnicoId) {
                return $this->errorResponse(
                    'No se pudo determinar el técnico. Verifique que su usuario esté correctamente vinculado.',
                    400
                );
            }

            $fechaHoy = today();

            $mantenimientos = MantProgramacion::with([
                'estadoMantenimiento',
                'tecnico',
                'centro:id_centro,nombre_centro,latitud,longitud,id_concesion',
                'centro.concesion:id_concesion,nombre',
                'via:via_id,nombre',
            ])
                ->activos()
                ->where('tecnico_asignado', $tecnicoId)
                ->where(function ($query) use ($fechaHoy) {
                    // Mantenimientos que inician hoy O que están en rango (inicio <= hoy <= fin)
                    $query->whereDate('fecha_programada', $fechaHoy)
                        ->orWhere(function ($q) use ($fechaHoy) {
                            $q->whereDate('fecha_programada', '<=', $fechaHoy)
                                ->whereDate('fecha_fin', '>=', $fechaHoy);
                        });
                })
                ->orderBy('fecha_programada', 'asc')
                ->orderBy('estado_id', 'asc')
                ->get();

            $resumen = [
                'total' => $mantenimientos->count(),
                'completados' => $mantenimientos->filter(
                    fn($m) => $m->estadoMantenimiento && in_array($m->estadoMantenimiento->estado_codigo, ['COMPLETADO', 'APROBADO'])
                )->count(),
                'en_progreso' => $mantenimientos->filter(
                    fn($m) => $m->estadoMantenimiento && in_array(
                        $m->estadoMantenimiento->estado_codigo,
                        ['CAMINO_PEAJE', 'LLEGADA_PEAJE', 'EN_MANTENIMIENTO', 'MANT_FINALIZADO', 'PEND_APROBACION']
                    )
                )->count(),
                'pendientes' => $mantenimientos->filter(
                    fn($m) => $m->estadoMantenimiento && $m->estadoMantenimiento->estado_codigo === 'PROGRAMADO'
                )->count(),
            ];

            return $this->successResponse([
                'fecha' => $fechaHoy->toDateString(),
                'tecnico' => [
                    'id' => $tecnicoId,
                    'nombre' => $usuario->nombre_completo,
                ],
                'resumen' => $resumen,
                'mantenimientos' => $this->mapMantenimientos($mantenimientos),
            ]);

        }, 'Error obteniendo mantenimientos del día');
    }
    #[OA\Get(
        path: "/api/v1/mantenimientos/{id}",
        summary: "Ver detalle de mantenimiento",
        description: "Obtiene información completa del mantenimiento incluyendo historial, checklist, evidencias y aprobación",
        operationId: "verMantenimiento",
        tags: ["Mantenimientos"],
        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 del mantenimiento"),
            new OA\Response(response: 404, description: "Mantenimiento no encontrado")
        ]
    )]
    public function show(int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($id) {
            $mantenimiento = MantProgramacion::with([
                'estadoMantenimiento',
                'tecnico:usu_id,usu_nombre,usu_apellido,usu_cedula,usu_email',
                'centro:id_centro,nombre_centro,id_concesion,latitud,longitud',
                'centro.concesion:id_concesion,nombre',
                'via:via_id,nombre,id_centro',
                'historialEstados.estadoAnterior',
                'historialEstados.estadoNuevo',
                'historialEstados.usuarioEjecuta',
                'checklistRespuestas.itemRevision',
                'checklistRespuestas.estadoEquipo',
                'checklistRespuestas.inventario.tipoHardware',
                'evidencias',
                'aprobacion.jefeOperativo:usu_id,usu_nombre,usu_apellido',
            ])->where('prog_id', $id)->first();

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

            // Lógica corregida para progreso y resumen por vías
            $itemsRevisionCount = ItemRevisionMantenimiento::activos()->count();

            // Obtener todas las vías del peaje
            $vias = ViaSubcentro::where('id_centro', $mantenimiento->id_centro)
                ->where('estado', 1)
                ->get();

            // Agrupar respuestas por vía
            $respuestasPorVia = $mantenimiento->checklistRespuestas->groupBy('via_id');

            $resumenVias = [];
            $totalItemsGlobal = 0;
            $itemsRespondidosGlobal = $mantenimiento->checklistRespuestas->count();

            foreach ($vias as $via) {
                // Obtener respuestas para esta vía
                $respuestasVia = $respuestasPorVia->get($via->via_id, collect());

                // Contar equipos únicos trabajados en esta vía
                $equiposUnicosCount = $respuestasVia->pluck('inventario_id')->unique()->count();

                // El total esperado depende de los equipos QUE SE HAN TOCADO
                $totalItemsVia = $equiposUnicosCount * $itemsRevisionCount;
                $respondidosVia = $respuestasVia->count();

                $porcentajeVia = $totalItemsVia > 0 ? round(($respondidosVia / $totalItemsVia) * 100, 2) : 0;

                // Determinar estado
                $estadoVia = 'pendiente';
                if ($equiposUnicosCount > 0) {
                    // Si hay equipos pero porcentaje < 100 es progreso. Si es 100 es completado.
                    // Pero cuidado: Si escaneo 1 equipo y lo termino, 100%.
                    // Si luego escaneo otro, baja el %.
                    // Asumimos 'completado' si lo trabajado está al 100%.
                    $estadoVia = ($porcentajeVia >= 100) ? 'completado' : 'en_progreso';
                }

                $resumenVias[] = [
                    'via_id' => $via->via_id,
                    'nombre' => $via->nombre,
                    'total_equipos' => $equiposUnicosCount, // Equipos "detectados"
                    'items_respondidos' => $respondidosVia,
                    'total_items_esperados' => $totalItemsVia,
                    'avance_porcentaje' => $porcentajeVia,
                    'estado' => $estadoVia
                ];

                $totalItemsGlobal += $totalItemsVia;
            }

            // Recalcular porcentaje global
            // Nota: El global también es dinámico según lo que se va encontrando
            $progresoChecklist = $totalItemsGlobal > 0 ? round(($itemsRespondidosGlobal / $totalItemsGlobal) * 100, 2) : 0;
            $totalEvidencias = $mantenimiento->evidencias->where('estado', 1)->count();

            return $this->successResponse([
                'mantenimiento' => [
                    'prog_id' => $mantenimiento->prog_id,
                    'fecha_programada' => $mantenimiento->fecha_programada,
                    'observaciones' => $mantenimiento->observaciones,
                    'qr_code' => $mantenimiento->qr_code,
                    'qr_expira' => $mantenimiento->qr_expira,
                    'qr_vigente' => $mantenimiento->qrEstaVigente(),
                    'estado' => [
                        'id' => $mantenimiento->estadoMantenimiento->estado_id,
                        'codigo' => $mantenimiento->estadoMantenimiento->estado_codigo,
                        'nombre' => $mantenimiento->estadoMantenimiento->estado_nombre,
                        'color' => $mantenimiento->estadoMantenimiento->color_hex,
                        'requiere_gps' => (bool) $mantenimiento->estadoMantenimiento->requiere_gps,
                    ],
                    'tecnico' => $mantenimiento->tecnico ? [
                        'id' => $mantenimiento->tecnico->usu_id,
                        'nombre' => $mantenimiento->tecnico->nombre_completo,
                        'cedula' => $mantenimiento->tecnico->usu_cedula,
                    ] : null,
                    'peaje' => $mantenimiento->centro ? [
                        'id' => $mantenimiento->centro->id_centro,
                        'nombre' => $mantenimiento->centro->nombre_centro,
                        'latitud' => $mantenimiento->centro->latitud,
                        'longitud' => $mantenimiento->centro->longitud,
                        'concesion' => $mantenimiento->centro->concesion?->nombre ?? 'Sin concesión',
                    ] : null,
                    'via' => $mantenimiento->via ? ['id' => $mantenimiento->via->via_id, 'nombre' => $mantenimiento->via->nombre] : null,
                ],
                'progreso' => [
                    'checklist_total' => $totalItemsGlobal,
                    'checklist_respondidos' => $itemsRespondidosGlobal,
                    'checklist_porcentaje' => $progresoChecklist,
                    'evidencias_total' => $totalEvidencias,
                    'evidencias_minimo' => 3,
                    'puede_finalizar' => $progresoChecklist >= 100 && $totalEvidencias >= 3,
                ],
                'resumen_vias' => $resumenVias,
                'historial' => $mantenimiento->historialEstados->map(fn($h) => [
                    'fecha' => $h->fecha_cambio,
                    'estado_anterior' => $h->estadoAnterior?->estado_nombre,
                    'estado_nuevo' => $h->estadoNuevo->estado_nombre,
                    'usuario' => $h->usuarioEjecuta?->nombre_completo,
                    'observaciones' => $h->observaciones,
                    'coordenadas' => $h->coordenadas,
                ]),
                'checklist' => $mantenimiento->checklistRespuestas->map(fn($c) => [
                    'respuesta_id' => $c->respuesta_id,
                    'item' => ['id' => $c->itemRevision->id, 'nombre' => $c->itemRevision->nombre],
                    'equipo' => $c->inventario ? ['id' => $c->inventario->inventario_id, 'descripcion' => $c->inventario->descripcion_completa] : null,
                    'estado_equipo' => ['id' => $c->estadoEquipo->estado_equipo_id, 'nombre' => $c->estadoEquipo->nombre, 'color' => $c->estadoEquipo->color_hex],
                    'observacion' => $c->observacion,
                    'valor_medicion' => $c->valor_medicion,
                    'fecha' => $c->fecha_registro,
                ]),
                'evidencias' => $mantenimiento->evidencias->where('estado', 1)->map(fn($e) => [
                    'evidencia_id' => $e->evidencia_id,
                    'tipo' => $e->tipo,
                    'nombre' => $e->nombre_archivo,
                    'url' => $e->url,
                    'descripcion' => $e->descripcion,
                    'coordenadas' => $e->tieneGps() ? ['lat' => $e->latitud, 'lng' => $e->longitud] : null,
                    'tamanio' => $e->tamanio_formateado,
                    'sync_status' => $e->sync_status,
                ]),
                'aprobacion' => $mantenimiento->aprobacion ? [
                    'fecha' => $mantenimiento->aprobacion->fecha_aprobacion,
                    'tipo' => $mantenimiento->aprobacion->tipo,
                    'jefe' => $mantenimiento->aprobacion->jefeOperativo?->nombre_completo,
                    'observaciones' => $mantenimiento->aprobacion->observaciones,
                    'motivo_rechazo' => $mantenimiento->aprobacion->motivo_rechazo,
                ] : null,
            ]);
        }, 'Error obteniendo detalle del mantenimiento');
    }

    #[OA\Put(
        path: "/api/v1/mantenimientos/{id}/estado",
        summary: "Cambiar estado del mantenimiento",
        description: "Cambia el estado del mantenimiento. Usa el SP sp_cambiar_estado_mant. Requiere GPS para ciertos estados.",
        operationId: "cambiarEstadoMantenimiento",
        tags: ["Mantenimientos"],
        security: [["sanctum" => []]],
        parameters: [new OA\Parameter(name: "id", in: "path", required: true, schema: new OA\Schema(type: "integer"))],
        requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(ref: "#/components/schemas/CambiarEstadoRequest")),
        responses: [
            new OA\Response(response: 200, description: "Estado actualizado"),
            new OA\Response(response: 400, description: "Error de validación o transición inválida"),
            new OA\Response(response: 403, description: "Sin permisos"),
            new OA\Response(response: 404, description: "Mantenimiento no encontrado")
        ]
    )]
    public function cambiarEstado(Request $request, int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($request, $id) {
            $request->validate([
                'estado' => 'required|string|in:CAMINO_PEAJE,LLEGADA_PEAJE,EN_MANTENIMIENTO,MANT_FINALIZADO,RETORNO_INICIADO,COMPLETADO',
                'latitud' => 'nullable|numeric|between:-90,90',
                'longitud' => 'nullable|numeric|between:-180,180',
                'precision' => 'nullable|numeric|min:0',
                'observaciones' => 'nullable|string|max:500',
            ]);

            $mantenimiento = MantProgramacion::where('prog_id', $id)->activos()->first();
            if (!$mantenimiento) {
                return $this->notFoundResponse('Mantenimiento no encontrado');
            }

            $nombrePerfil = $this->getNombrePerfil();
            $esAdmin = $nombrePerfil && in_array($nombrePerfil, ['SISTEMAS', 'ADMINISTRACION', 'MESA_AYUDA']);
            $tecnicoId = $this->getTecnicoId();

            if (!$esAdmin && $mantenimiento->tecnico_asignado != $tecnicoId) {
                return $this->forbiddenResponse('No tiene permiso para modificar este mantenimiento');
            }

            // Usar usu_id (tabla usuarios) en lugar de users.id para el SP
            $usuarioIdSP = $this->getTecnicoId() ?? $this->usuarioId();

            $resultado = $this->ejecutarSP('sp_cambiar_estado_mant', [
                $id,
                $request->estado,
                $request->latitud,
                $request->longitud,
                $request->precision,
                $request->observaciones,
                $usuarioIdSP,
            ]);

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

            if (!($respuesta['success'] ?? false)) {
                return $this->errorResponse(
                    $respuesta['message'] ?? 'Error al cambiar estado',
                    400,
                    ['code' => $respuesta['code'] ?? 'ERROR']
                );
            }

            // Recargar mantenimiento con relaciones para devolver datos completos
            $mantenimiento->refresh();
            $mantenimiento->load(['estadoMantenimiento', 'tecnico', 'centro.concesion', 'via']);

            return $this->successResponse(
                ['mantenimiento' => $this->mapMantenimiento($mantenimiento, true)],
                $respuesta['message'] ?? 'Estado actualizado exitosamente'
            );
        }, 'Error cambiando estado del mantenimiento');
    }

    #[OA\Get(
        path: "/api/v1/mantenimientos/{id}/historial",
        summary: "Obtener historial de estados",
        description: "Retorna el historial de cambios de estado del mantenimiento con coordenadas GPS",
        operationId: "historialMantenimiento",
        tags: ["Mantenimientos"],
        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: "Historial de estados"),
            new OA\Response(response: 404, description: "Mantenimiento no encontrado")
        ]
    )]
    public function historial(int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($id) {
            $mantenimiento = MantProgramacion::where('prog_id', $id)->first();
            if (!$mantenimiento) {
                return $this->notFoundResponse('Mantenimiento no encontrado');
            }

            $historial = MantEstadoHistorial::with([
                'estadoAnterior:estado_id,estado_codigo,estado_nombre,color_hex',
                'estadoNuevo:estado_id,estado_codigo,estado_nombre,color_hex',
                'usuarioEjecuta',
            ])->where('prog_id', $id)->orderBy('fecha_cambio', 'desc')->get();

            return $this->successResponse([
                'prog_id' => $id,
                'historial' => $historial->map(fn($h) => [
                    'historial_id' => $h->historial_id,
                    'fecha' => $h->fecha_cambio,
                    'estado_anterior' => $h->estadoAnterior ? ['codigo' => $h->estadoAnterior->estado_codigo, 'nombre' => $h->estadoAnterior->estado_nombre, 'color' => $h->estadoAnterior->color_hex] : null,
                    'estado_nuevo' => ['codigo' => $h->estadoNuevo->estado_codigo, 'nombre' => $h->estadoNuevo->estado_nombre, 'color' => $h->estadoNuevo->color_hex],
                    'usuario' => $h->usuarioEjecuta ? ['id' => $h->usuarioEjecuta->id, 'nombre' => $h->usuarioEjecuta->nombre_completo] : null,
                    'observaciones' => $h->observaciones,
                    'gps' => $h->tieneGps() ? ['latitud' => $h->latitud, 'longitud' => $h->longitud, 'precision' => $h->precision_gps] : null,
                ]),
            ]);
        }, 'Error obteniendo historial');
    }

    #[OA\Get(
        path: "/api/v1/mantenimientos/{id}/checklist",
        summary: "Obtener checklist del mantenimiento",
        description: "Retorna el checklist de items a revisar por equipo con respuestas existentes",
        operationId: "getChecklistMantenimiento",
        tags: ["Mantenimientos"],
        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: "Checklist del mantenimiento"),
            new OA\Response(response: 404, description: "Mantenimiento no encontrado")
        ]
    )]
    public function getChecklist(int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($id) {
            $mantenimiento = MantProgramacion::where('prog_id', $id)->first();
            if (!$mantenimiento) {
                return $this->notFoundResponse('Mantenimiento no encontrado');
            }

            $items = ItemRevisionMantenimiento::activos()->ordenados()->get();
            $respuestasExistentes = MantChecklistRespuesta::where('prog_id', $id)->get()->keyBy(fn($r) => "{$r->inventario_id}_{$r->id_item}");

            // Obtener vías del peaje
            $vias = ViaSubcentro::where('id_centro', $mantenimiento->id_centro)
                ->where('estado', 1)
                ->get();

            // Obtener TODO el inventario de equipos activos DE VÍA
            // Los equipos no están asociados directamente a centros,
            // la asociación se hace a través de las respuestas del checklist
            // FILTRO: Solo equipos cuyo tipo de hardware es "de vía" (es_de_via=1)
            $inventario = HardwareInventario::with(['tipoHardware', 'marca'])
                ->whereHas('tipoHardware', function ($q) {
                    $q->where('es_de_via', 1)->where('estado', 1);
                })
                ->activos()
                ->get();

            $estadosEquipo = DB::table('mant_estado_equipos')->where('estado', 1)->orderBy('estado_equipo_id')->get();

            // Estructura plana (mantener compatibilidad)
            $checklist = [];
            foreach ($inventario as $equipo) {
                $equipoChecklist = [
                    'equipo' => [
                        'inventario_id' => $equipo->inventario_id,
                        'tipo' => $equipo->tipoHardware?->nombre,
                        'marca' => $equipo->marca?->nombre,
                        'modelo' => $equipo->modelo,
                        'serie' => $equipo->serie
                    ],
                    'items' => [],
                ];
                foreach ($items as $item) {
                    $key = "{$equipo->inventario_id}_{$item->id_item}";
                    $respuesta = $respuestasExistentes->get($key);
                    $equipoChecklist['items'][] = [
                        'id_item' => $item->id_item, // FIX: usar id_item (primary key) en lugar de id
                        'nombre' => $item->nombre,
                        'descripcion' => $item->descripcion,
                        'obligatorio' => $item->esObligatorio(),
                        'respondido' => $respuesta !== null,
                        'respuesta' => $respuesta ? [
                            'respuesta_id' => $respuesta->respuesta_id,
                            'estado_equipo_id' => $respuesta->estado_equipo_id,
                            'valor_medicion' => $respuesta->valor_medicion,
                            'observacion' => $respuesta->observacion
                        ] : null,
                    ];
                }
                $checklist[] = $equipoChecklist;
            }

            // Obtener tipos de hardware de vía con items de checklist configurados
            $tiposHardware = \App\Models\HardwareMaestro::deVia()
                ->where('estado', 1)
                ->get();

            // Filtrar solo los que tienen items de checklist activos
            $tiposConChecklist = $tiposHardware->filter(function ($tipo) {
                return \App\Models\ChecklistMantenimientoVia::where('hardware_id', $tipo->hardware_id)
                    ->where('estado', 1)
                    ->exists();
            });

            $cantidadCategorias = $tiposConChecklist->count();

            // Respuestas indexadas por via_id + inventario_id + id_item
            $respuestasPorVia = MantChecklistRespuesta::where('prog_id', $id)->get();

            // Nueva estructura agrupada por vía
            $checklistVias = [];

            foreach ($vias as $via) {
                $equiposArray = [];

                // Contar items respondidos para esta vía
                $respondidosVia = $respuestasPorVia->filter(function ($r) use ($via) {
                    return $r->via_id == $via->via_id;
                })->count();

                // Total de items por vía = categorías con checklist * items de cada categoría
                $totalItemsVia = 0;

                foreach ($tiposConChecklist as $tipo) {
                    // Contar items de checklist para este tipo
                    $itemsDelTipo = \App\Models\ChecklistMantenimientoVia::where('hardware_id', $tipo->hardware_id)
                        ->where('estado', 1)
                        ->count();

                    $totalItemsVia += $itemsDelTipo;

                    // Buscar equipo registrado en esta vía para este tipo
                    $equipoRegistrado = HardwareInventario::where('maestro_id', $tipo->hardware_id)
                        ->where('via_id', $via->via_id)
                        ->where('estado', 1)
                        ->first();

                    $itemsRespondidosTipo = 0;
                    if ($equipoRegistrado) {
                        $itemsRespondidosTipo = $respuestasPorVia->filter(function ($r) use ($equipoRegistrado, $via) {
                            return $r->inventario_id == $equipoRegistrado->inventario_id && $r->via_id == $via->via_id;
                        })->count();
                    }

                    $equiposArray[] = [
                        'inventario_id' => $equipoRegistrado?->inventario_id,
                        'tipo' => $tipo->nombre,
                        'marca' => $equipoRegistrado?->marca?->nombre,
                        'modelo' => $equipoRegistrado?->modelo,
                        'serie' => $equipoRegistrado?->serie,
                        'items_respondidos' => $itemsRespondidosTipo,
                        'total_items' => $itemsDelTipo,
                        'completo' => $itemsDelTipo > 0 && $itemsRespondidosTipo == $itemsDelTipo,
                    ];
                }

                // Incluir todas las vías con info resumida por categoría
                $checklistVias[] = [
                    'via_id' => $via->via_id,
                    'nombre' => $via->nombre,
                    'cantidad_equipos' => $cantidadCategorias,
                    'equipos' => $equiposArray,
                    'progreso' => [
                        'total' => $totalItemsVia,
                        'respondidos' => $respondidosVia,
                        'porcentaje' => $totalItemsVia > 0 ? round(($respondidosVia / $totalItemsVia) * 100, 2) : 0
                    ]
                ];
            }

            // Progreso general: total items de todas las vías
            $totalVias = $vias->count();
            $totalItems = 0;
            foreach ($tiposConChecklist as $tipo) {
                $itemsDelTipo = \App\Models\ChecklistMantenimientoVia::where('hardware_id', $tipo->hardware_id)
                    ->where('estado', 1)
                    ->count();
                $totalItems += $itemsDelTipo;
            }
            $totalItems = $totalItems * $totalVias;
            $respondidos = $respuestasPorVia->count();

            return $this->successResponse([
                'prog_id' => $id,
                'checklist' => $checklist, // Mantener compatibilidad
                'checklist_vias' => $checklistVias, // Nueva estructura agrupada
                'estados_equipo' => $estadosEquipo->map(fn($e) => [
                    'id' => $e->estado_equipo_id,
                    'codigo' => $e->codigo,
                    'nombre' => $e->nombre,
                    'color' => $e->color_hex,
                    'icono' => $e->icono
                ]),
                'progreso' => [
                    'total' => $totalItems,
                    'respondidos' => $respondidos,
                    'porcentaje' => $totalItems > 0 ? round(($respondidos / $totalItems) * 100, 2) : 0
                ],
            ]);
        }, 'Error obteniendo checklist');
    }

    #[OA\Post(
        path: "/api/v1/mantenimientos/{id}/checklist",
        summary: "Guardar respuesta de checklist",
        description: "Guarda una respuesta individual del checklist. Solo disponible en estado EN_MANTENIMIENTO.",
        operationId: "guardarChecklistMantenimiento",
        tags: ["Mantenimientos"],
        security: [["sanctum" => []]],
        parameters: [new OA\Parameter(name: "id", in: "path", required: true, schema: new OA\Schema(type: "integer"))],
        requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(ref: "#/components/schemas/GuardarChecklistRequest")),
        responses: [
            new OA\Response(response: 200, description: "Checklist guardado"),
            new OA\Response(response: 400, description: "Estado incorrecto o error de validación"),
            new OA\Response(response: 404, description: "Mantenimiento no encontrado")
        ]
    )]
    public function guardarChecklist(Request $request, int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($request, $id) {
            $request->validate([
                'inventario_id' => 'required|integer|exists:hardware_inventario,inventario_id',
                'via_id' => 'required|integer|exists:via_subcentro,via_id',
                'id_item' => 'required|integer|exists:items_revision_mantenimiento,id_item',
                'estado_equipo_id' => 'required|integer|exists:mant_estado_equipos,estado_equipo_id',
                'valor_medicion' => 'nullable|string|max:100',
                'observacion' => 'nullable|string|max:1000',
            ]);

            $mantenimiento = MantProgramacion::where('prog_id', $id)->activos()->first();
            if (!$mantenimiento) {
                return $this->notFoundResponse('Mantenimiento no encontrado');
            }

            if ($mantenimiento->codigo_estado !== 'EN_MANTENIMIENTO') {
                return $this->errorResponse('Solo se puede llenar checklist cuando está EN_MANTENIMIENTO', 400, ['codigo_actual' => $mantenimiento->codigo_estado]);
            }

            // Validar que la vía pertenece al peaje del mantenimiento
            $viaValida = DB::table('via_subcentro')
                ->where('via_id', $request->via_id)
                ->where('id_centro', $mantenimiento->id_centro)
                ->where('estado', 1)
                ->exists();

            if (!$viaValida) {
                return $this->errorResponse('La vía seleccionada no pertenece a este peaje', 400);
            }

            $resultado = $this->ejecutarSP('sp_guardar_checklist', [
                $id,
                $request->inventario_id,
                $request->via_id,
                $request->id_item,
                $request->estado_equipo_id,
                $request->valor_medicion,
                $request->observacion,
                $this->usuarioId()
            ]);
            $respuesta = $this->parsearRespuestaSP($resultado);

            if (!($respuesta['success'] ?? false)) {
                return $this->errorResponse($respuesta['message'] ?? 'Error al guardar checklist', 400);
            }

            // Contar items respondidos
            $respondidos = MantChecklistRespuesta::where('prog_id', $id)->count();
            $totalItems = ItemRevisionMantenimiento::activos()->count();

            return $this->successResponse([
                'prog_id' => $id,
                'item_guardado' => [
                    'inventario_id' => $request->inventario_id,
                    'via_id' => $request->via_id,
                    'id_item' => $request->id_item
                ],
                'progreso' => [
                    'respondidos' => $respondidos,
                    'total_items_checklist' => $totalItems,
                ],
            ], 'Checklist guardado exitosamente');
        }, 'Error guardando checklist');
    }

    #[OA\Post(
        path: "/api/v1/mantenimientos/{id}/checklist/batch",
        summary: "Guardar múltiples respuestas de checklist",
        description: "Guarda múltiples respuestas del checklist en lote. Ideal para sincronización offline.",
        operationId: "guardarChecklistBatch",
        tags: ["Mantenimientos"],
        security: [["sanctum" => []]],
        parameters: [new OA\Parameter(name: "id", in: "path", required: true, schema: new OA\Schema(type: "integer"))],
        requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent()),
        responses: [new OA\Response(response: 200, description: "Respuestas procesadas")]
    )]
    public function guardarChecklistBatch(Request $request, int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($request, $id) {
            $request->validate([
                'respuestas' => 'required|array|min:1',
                'respuestas.*.inventario_id' => 'required|integer',
                'respuestas.*.via_id' => 'required|integer',
                'respuestas.*.id_item' => 'required|integer',
                'respuestas.*.estado_equipo_id' => 'required|integer',
                'respuestas.*.valor_medicion' => 'nullable|string|max:100',
                'respuestas.*.observacion' => 'nullable|string|max:1000',
            ]);

            $mantenimiento = MantProgramacion::where('prog_id', $id)->activos()->first();
            if (!$mantenimiento) {
                return $this->notFoundResponse('Mantenimiento no encontrado');
            }

            if ($mantenimiento->codigo_estado !== 'EN_MANTENIMIENTO') {
                return $this->errorResponse('Solo se puede llenar checklist cuando está EN_MANTENIMIENTO', 400);
            }

            $guardados = 0;
            $errores = [];

            DB::beginTransaction();
            try {
                foreach ($request->respuestas as $index => $resp) {
                    try {
                        $resultado = $this->ejecutarSP('sp_guardar_checklist', [
                            $id,
                            $resp['inventario_id'],
                            $resp['via_id'],
                            $resp['id_item'],
                            $resp['estado_equipo_id'],
                            $resp['valor_medicion'] ?? null,
                            $resp['observacion'] ?? null,
                            $this->usuarioId()
                        ]);
                        $respuestaSP = $this->parsearRespuestaSP($resultado);
                        if ($respuestaSP['success'] ?? false) {
                            $guardados++;
                        } else {
                            $errores[] = ['index' => $index, 'error' => $respuestaSP['message'] ?? 'Error desconocido'];
                        }
                    } catch (\Exception $e) {
                        $errores[] = ['index' => $index, 'error' => 'Error procesando item'];
                    }
                }
                DB::commit();

                return $this->successResponse(['guardados' => $guardados, 'errores' => $errores], "Se guardaron {$guardados} respuestas");
            } catch (\Exception $e) {
                DB::rollBack();
                throw $e;
            }
        }, 'Error guardando checklist batch');
    }

    #[OA\Post(
        path: "/api/v1/mantenimientos/{id}/finalizar",
        summary: "Finalizar mantenimiento",
        description: "Finaliza el mantenimiento y genera código QR para aprobación. Requiere checklist 100% y mínimo 3 evidencias.",
        operationId: "finalizarMantenimiento",
        tags: ["Mantenimientos"],
        security: [["sanctum" => []]],
        parameters: [new OA\Parameter(name: "id", in: "path", required: true, schema: new OA\Schema(type: "integer"))],
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(
                required: ["latitud", "longitud"],
                properties: [
                    new OA\Property(property: "latitud", type: "number", format: "float", example: -0.1807),
                    new OA\Property(property: "longitud", type: "number", format: "float", example: -78.4678)
                ]
            )
        ),
        responses: [
            new OA\Response(response: 200, description: "Mantenimiento finalizado y QR generado"),
            new OA\Response(response: 400, description: "Requisitos no cumplidos")
        ]
    )]
    public function finalizar(Request $request, int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($request, $id) {
            $request->validate([
                'latitud' => 'required|numeric|between:-90,90',
                'longitud' => 'required|numeric|between:-180,180',
            ]);

            $mantenimiento = MantProgramacion::where('prog_id', $id)->activos()->first();
            if (!$mantenimiento) {
                return $this->notFoundResponse('Mantenimiento no encontrado');
            }

            $resultado = $this->ejecutarSP('sp_finalizar_mantenimiento', [$id, $request->latitud, $request->longitud, $this->usuarioId()]);
            $respuesta = $this->parsearRespuestaSP($resultado);

            if (!($respuesta['success'] ?? false)) {
                return $this->errorResponse($respuesta['message'] ?? 'Error al finalizar mantenimiento', 400, ['code' => $respuesta['code'] ?? 'ERROR']);
            }

            $mantenimiento->refresh();

            return $this->successResponse(['prog_id' => $id, 'qr_code' => $mantenimiento->qr_code, 'qr_expira' => $mantenimiento->qr_expira], 'Mantenimiento finalizado. QR generado para aprobación.');
        }, 'Error finalizando mantenimiento');
    }

    /*
    /**
     * Obtener equipos (tipos de hardware) por vía
     *
     * @param int $id ID del mantenimiento
     * @param int $viaId ID de la vía
     * @return JsonResponse
     */
    /*
    public function getEquiposPorVia(int $id, int $viaId): JsonResponse
    {
        return $this->ejecutar(function () use ($id, $viaId) {
            // Verificar que el mantenimiento existe
            $mantenimiento = MantProgramacion::where('prog_id', $id)->first();
            if (!$mantenimiento) {
                return $this->notFoundResponse('Mantenimiento no encontrado');
            }

            // Verificar que la vía existe y pertenece al centro del mantenimiento
            $via = ViaSubcentro::where('via_id', $viaId)
                ->where('id_centro', $mantenimiento->id_centro)
                ->where('estado', 1)
                ->first();

            if (!$via) {
                return $this->notFoundResponse('Vía no encontrada o no pertenece a este peaje');
            }

            // Obtener todos los tipos de hardware marcados como "de vía" y activos
            $tiposHardware = \App\Models\HardwareMaestro::deVia()
                ->where('estado', 1)
                ->get();

            // Construir la respuesta
            $equipos = [];
            foreach ($tiposHardware as $tipo) {
                // Obtener items de checklist configurados para este tipo de hardware
                $itemsChecklist = \App\Models\ChecklistMantenimientoVia::where('hardware_id', $tipo->hardware_id)
                    ->where('estado', 1)
                    ->with('itemRevision')
                    ->get();

                $items = [];
                foreach ($itemsChecklist as $checklistItem) {
                    if ($checklistItem->itemRevision) {
                        $items[] = [
                            'id_item' => $checklistItem->itemRevision->id_item,
                            'nombre' => $checklistItem->itemRevision->nombre,
                            'descripcion' => $checklistItem->itemRevision->descripcion,
                            'obligatorio' => $checklistItem->itemRevision->esObligatorio(),
                            'tipo_respuesta' => $checklistItem->itemRevision->tipo_respuesta,
                        ];
                    }
                }

                // Solo agregar el tipo de hardware si tiene items de checklist
                if (count($items) > 0) {
                    // Buscar equipo asociado a esta vía por último movimiento en movimiento_inventario
                    // Lógica: buscar en movimiento_inventario el último registro donde via_id = viaId
                    // y cuyo inventario pertenezca a este tipo de hardware (maestro_id)
                    $equipoAsignado = HardwareInventario::with(['marca'])
                        ->where('maestro_id', $tipo->hardware_id)
                        ->where('estado', 1)
                        ->whereHas('movimientos', function ($q) use ($viaId) {
                            $q->where('via_id', $viaId);
                        })
                        ->get()
                        ->filter(function ($equipo) use ($viaId) {
                            // Verificar que el ÚLTIMO movimiento de este equipo sea en esta vía
                            $ultimoMov = \App\Models\MovimientoInventario::where('inventario_id', $equipo->inventario_id)
                                ->orderBy('fecha', 'desc')
                                ->orderBy('movimiento_id', 'desc')
                                ->first();
                            return $ultimoMov && $ultimoMov->via_id == $viaId;
                        })
                        ->first();

                    // Si no se encontró por movimiento, intentar por via_id directo en hardware_inventario
                    if (!$equipoAsignado) {
                        $equipoAsignado = HardwareInventario::with(['marca'])
                            ->where('maestro_id', $tipo->hardware_id)
                            ->where('via_id', $viaId)
                            ->where('estado', 1)
                            ->first();
                    }

                    $inventarioId = null;
                    $codigo = null;
                    $progreso = null;
                    $equipoDetalle = null;

                    if ($equipoAsignado) {
                        $inventarioId = $equipoAsignado->inventario_id;
                        $codigo = $equipoAsignado->codigo1 ?? $equipoAsignado->codigo2;

                        // Calcular progreso real desde mant_checklist_respuestas
                        $totalItems = count($items);
                        $itemsRespondidos = MantChecklistRespuesta::where('prog_id', $id)
                            ->where('inventario_id', $equipoAsignado->inventario_id)
                            ->where('via_id', $viaId)
                            ->count();

                        $progreso = $totalItems > 0
                            ? (int) round(($itemsRespondidos / $totalItems) * 100)
                            : 0;

                        // Obtener último movimiento
                        $ultimoMov = \App\Models\MovimientoInventario::where('inventario_id', $equipoAsignado->inventario_id)
                            ->orderBy('fecha', 'desc')
                            ->orderBy('movimiento_id', 'desc')
                            ->first();

                        // Detalle completo del equipo asignado
                        $equipoDetalle = [
                            'marca' => $equipoAsignado->marca?->nombre ?? 'S/N',
                            'marca_id' => $equipoAsignado->marca_id,
                            'modelo' => $equipoAsignado->modelo ?? 'Sin modelo',
                            'codigo1' => $equipoAsignado->codigo1,
                            'codigo2' => $equipoAsignado->codigo2,
                            'observacion' => $equipoAsignado->observacion,
                            'estado' => $equipoAsignado->estado,
                            'ultimo_movimiento' => $ultimoMov ? [
                                'fecha' => $ultimoMov->fecha?->format('Y-m-d H:i'),
                                'observacion' => $ultimoMov->observacion,
                                'estado' => $ultimoMov->estado_descripcion,
                            ] : null,
                        ];
                    }

                    $equipos[] = [
                        'tipo_hardware' => [
                            'hardware_id' => $tipo->hardware_id,
                            'nombre' => $tipo->nombre,
                            'descripcion' => $tipo->descripcion,
                        ],
                        'items_checklist' => $items,
                        'inventario_id' => $inventarioId,
                        'codigo' => $codigo,
                        'progreso' => $progreso,
                        'equipo_detalle' => $equipoDetalle,
                    ];
                }
            }

            return $this->successResponse([
                'via' => [
                    'via_id' => $via->via_id,
                    'nombre' => $via->nombre,
                ],
                'equipos' => $equipos
            ], 'Equipos de vía obtenidos exitosamente');

        }, 'Error obteniendo equipos de vía');
    }

    /**
     * Buscar equipo por código
     * GET /api/v1/mantenimientos/{id}/equipos/buscar?codigo=XXX&hardware_id=YYY
     */
    public function buscarEquipo(Request $request, int $id): JsonResponse
    {
        return $this->ejecutar(function () use ($request, $id) {

            $request->validate([
                'codigo' => 'required|string|max:100',
                'hardware_id' => 'required|integer',
            ]);

            // Verificar que el mantenimiento existe
            $mantenimiento = MantProgramacion::where('prog_id', $id)->first();
            if (!$mantenimiento) {
                return $this->notFoundResponse('Mantenimiento no encontrado');
            }

            // Buscar equipo por código (codigo1 o codigo2) y tipo de hardware
            $equipo = HardwareInventario::where('maestro_id', $request->hardware_id)
                ->where(function ($q) use ($request) {
                    $q->where('codigo1', $request->codigo)
                        ->orWhere('codigo2', $request->codigo);
                })
                ->with(['tipoHardware', 'marca', 'via'])
                ->first();

            if (!$equipo) {
                return $this->successResponse([
                    'encontrado' => false,
                    'mensaje' => 'Equipo no encontrado. Se creará uno nuevo al registrar.',
                ]);
            }

            // Obtener último movimiento
            $ultimoMovimiento = \App\Models\MovimientoInventario::where('inventario_id', $equipo->inventario_id)
                ->orderBy('fecha', 'desc')
                ->first();

            return $this->successResponse([
                'encontrado' => true,
                'equipo' => [
                    'inventario_id' => $equipo->inventario_id,
                    'tipo_hardware' => $equipo->tipoHardware?->nombre,
                    'marca' => $equipo->marca?->nombre,
                    'marca_id' => $equipo->marca_id,
                    'modelo' => $equipo->modelo,
                    'codigo1' => $equipo->codigo1,
                    'codigo2' => $equipo->codigo2,
                    'observacion' => $equipo->observacion,
                    'via_actual' => $equipo->via?->nombre,
                    'via_id' => $equipo->via_id,
                    'estado' => $equipo->estado,
                ],
                'ultimo_movimiento' => $ultimoMovimiento ? [
                    'fecha' => $ultimoMovimiento->fecha,
                    'via' => $ultimoMovimiento->via?->nombre,
                    'observacion' => $ultimoMovimiento->observacion,
                    'estado' => $ultimoMovimiento->estado_descripcion,
                ] : null,
            ]);

        }, 'Error buscando equipo');
    }

    /**
     * Busca el equipo actualmente asignado a una vía para un tipo de hardware específico.
     *
     * Lógica:
     * 1. Buscar en movimiento_inventario equipos de este tipo con movimientos activos en esta vía
     * 2. Verificar que el último movimiento global del equipo sea en esta vía
     * 3. Fallback: buscar por hardware_inventario.via_id (equipos nuevos)
     *
     * @param int $hardwareId Tipo de hardware (maestro_id)
     * @param int $viaId ID de la vía
     * @return HardwareInventario|null
     */
    private function buscarEquipoEnVia(int $hardwareId, int $viaId): ?HardwareInventario
    {
        // Paso 1: Obtener inventario_ids de equipos de este tipo con movimientos activos en esta vía
        $inventarioIds = DB::table('movimiento_inventario as mi')
            ->join('hardware_inventario as hi', 'hi.inventario_id', '=', 'mi.inventario_id')
            ->where('hi.maestro_id', $hardwareId)
            ->where('mi.via_id', $viaId)
            ->where('hi.estado', 1)
            ->distinct()
            ->pluck('mi.inventario_id');

        if ($inventarioIds->isEmpty()) {
            // Fallback: buscar por hardware_inventario.via_id (equipos del nuevo sistema)
            return HardwareInventario::with(['marca'])
                ->where('maestro_id', $hardwareId)
                ->where('via_id', $viaId)
                ->where('estado', 1)
                ->first();
        }

        // Paso 2: Para cada equipo, verificar que su último movimiento global sea en esta vía
        $equipoValido = null;
        $fechaUltimoMov = null;

        foreach ($inventarioIds as $invId) {
            $ultimoMovGlobal = DB::table('movimiento_inventario')
                ->where('inventario_id', $invId)
                ->orderBy('fecha', 'desc')
                ->orderBy('movimiento_id', 'desc')
                ->first();

            if ($ultimoMovGlobal && $ultimoMovGlobal->via_id == $viaId) {
                if (!$fechaUltimoMov || $ultimoMovGlobal->fecha > $fechaUltimoMov) {
                    $equipoValido = $invId;
                    $fechaUltimoMov = $ultimoMovGlobal->fecha;
                }
            }
        }

        if ($equipoValido) {
            return HardwareInventario::with(['marca'])->find($equipoValido);
        }

        // Fallback final
        return HardwareInventario::with(['marca'])
            ->where('maestro_id', $hardwareId)
            ->where('via_id', $viaId)
            ->where('estado', 1)
            ->first();
    }

    /**
     * Obtener equipos (tipos de hardware) por vía
     */
    public function getEquiposPorVia(int $id, int $viaId): JsonResponse
    {
        return $this->ejecutar(function () use ($id, $viaId) {
            $mantenimiento = MantProgramacion::where('prog_id', $id)->first();
            if (!$mantenimiento) {
                return $this->notFoundResponse('Mantenimiento no encontrado');
            }

            $via = ViaSubcentro::where('via_id', $viaId)
                ->where('id_centro', $mantenimiento->id_centro)
                ->where('estado', 1)
                ->first();

            if (!$via) {
                return $this->notFoundResponse('Vía no encontrada o no pertenece a este peaje');
            }

            $tiposHardware = \App\Models\HardwareMaestro::deVia()
                ->where('estado', 1)
                ->get();

            $equipos = [];
            foreach ($tiposHardware as $tipo) {
                $itemsChecklist = \App\Models\ChecklistMantenimientoVia::where('hardware_id', $tipo->hardware_id)
                    ->where('estado', 1)
                    ->with('itemRevision')
                    ->get();

                $items = [];
                foreach ($itemsChecklist as $checklistItem) {
                    if ($checklistItem->itemRevision) {
                        $items[] = [
                            'id_item' => $checklistItem->itemRevision->id_item,
                            'nombre' => $checklistItem->itemRevision->nombre,
                            'descripcion' => $checklistItem->itemRevision->descripcion,
                            'obligatorio' => $checklistItem->itemRevision->esObligatorio(),
                            'tipo_respuesta' => $checklistItem->itemRevision->tipo_respuesta,
                        ];
                    }
                }

                if (count($items) > 0) {
                    // *** BÚSQUEDA CORREGIDA: usa movimiento_inventario.via_id con mi.estado = 1 ***
                    $equipoAsignado = $this->buscarEquipoEnVia($tipo->hardware_id, $viaId);

                    $inventarioId = null;
                    $codigo = null;
                    $progreso = null;
                    $equipoDetalle = null;

                    if ($equipoAsignado) {
                        $inventarioId = $equipoAsignado->inventario_id;
                        $codigo = $equipoAsignado->codigo1 ?? $equipoAsignado->codigo2;

                        $totalItems = count($items);
                        $itemsRespondidos = MantChecklistRespuesta::where('prog_id', $id)
                            ->where('inventario_id', $equipoAsignado->inventario_id)
                            ->where('via_id', $viaId)
                            ->count();

                        $progreso = $totalItems > 0
                            ? (int) round(($itemsRespondidos / $totalItems) * 100)
                            : 0;

                        $ultimoMov = \App\Models\MovimientoInventario::where('inventario_id', $equipoAsignado->inventario_id)
                            ->orderBy('fecha', 'desc')
                            ->orderBy('movimiento_id', 'desc')
                            ->first();

                        $equipoDetalle = [
                            'marca' => $equipoAsignado->marca?->nombre ?? 'S/N',
                            'marca_id' => $equipoAsignado->marca_id,
                            'modelo' => $equipoAsignado->modelo ?? 'Sin modelo',
                            'codigo1' => $equipoAsignado->codigo1,
                            'codigo2' => $equipoAsignado->codigo2,
                            'observacion' => $equipoAsignado->observacion,
                            'estado' => $equipoAsignado->estado,
                            'ultimo_movimiento' => $ultimoMov ? [
                                'fecha' => $ultimoMov->fecha?->format('Y-m-d H:i'),
                                'observacion' => $ultimoMov->observacion,
                                'estado' => $ultimoMov->estado_descripcion,
                            ] : null,
                        ];
                    }

                    $equipos[] = [
                        'tipo_hardware' => [
                            'hardware_id' => $tipo->hardware_id,
                            'nombre' => $tipo->nombre,
                            'descripcion' => $tipo->descripcion,
                        ],
                        'items_checklist' => $items,
                        'inventario_id' => $inventarioId,
                        'codigo' => $codigo,
                        'progreso' => $progreso,
                        'equipo_detalle' => $equipoDetalle,
                    ];
                }
            }

            return $this->successResponse([
                'via' => [
                    'via_id' => $via->via_id,
                    'nombre' => $via->nombre,
                ],
                'equipos' => $equipos
            ], 'Equipos de vía obtenidos exitosamente');

        }, 'Error obteniendo equipos de vía');
    }
    /**
     * Registrar equipo en vía
     * Busca o crea el equipo en inventario y registra el movimiento
     *
     * @param Request $request
     * @param int $id ID del mantenimiento
     * @param int $viaId ID de la vía
     * @return JsonResponse
     */
    public function registrarEquipo(Request $request, int $id, int $viaId): JsonResponse
    {
        return $this->ejecutar(function () use ($request, $id, $viaId) {
            // Validar request
            $request->validate([
                'hardware_id' => 'required|integer|exists:hardware_maestro,hardware_id',
                'codigo' => 'required|string|max:100',
                'marca_id' => 'nullable|integer|exists:hardware_marca,marca_id',
                'modelo' => 'nullable|string|max:100',
                'observacion' => 'nullable|string|max:500',
            ]);

            // Verificar que el mantenimiento existe
            $mantenimiento = MantProgramacion::where('prog_id', $id)->first();
            if (!$mantenimiento) {
                return $this->notFoundResponse('Mantenimiento no encontrado');
            }

            // Verificar que la vía existe y pertenece al centro del mantenimiento
            $via = ViaSubcentro::where('via_id', $viaId)
                ->where('id_centro', $mantenimiento->id_centro)
                ->where('estado', 1)
                ->first();

            if (!$via) {
                return $this->notFoundResponse('Vía no encontrada o no pertenece a este peaje');
            }

            // Buscar equipo por código (codigo1 o codigo2) y tipo de hardware
            $equipo = HardwareInventario::where('maestro_id', $request->hardware_id)
                ->where(function ($q) use ($request) {
                    $q->where('codigo1', $request->codigo)
                        ->orWhere('codigo2', $request->codigo);
                })
                ->first();

            $esNuevo = false;

            if (!$equipo) {
                // Crear nuevo equipo en inventario
                $marcaId = $request->input('marca_id', 5); // 5 = S/N (Sin marca)
                if (empty($marcaId)) {
                    $marcaId = 5;
                }
                $equipo = HardwareInventario::create([
                    'maestro_id' => $request->hardware_id,
                    'marca_id' => $marcaId,
                    'modelo' => $request->input('modelo', 'Sin modelo') ?: 'Sin modelo',
                    'codigo1' => $request->codigo,
                    'via_id' => $viaId,
                    'observacion' => $request->input('observacion', 'Registro de equipo en mantenimiento') ?: 'Registro de equipo en mantenimiento',
                    'estado' => 1,
                ]);
                $esNuevo = true;
            } else {
                // Actualizar vía actual del equipo y marcarlo como operativo
                $equipo->update([
                    'via_id' => $viaId,
                    'estado' => 1,
                ]);
            }

            // Registrar movimiento
            $movimiento = \App\Models\MovimientoInventario::create([
                'inventario_id' => $equipo->inventario_id,
                'via_id' => $viaId,
                'fecha' => now(),
                'observacion' => $request->observacion ?? 'Registro de equipo en mantenimiento',
                'estado' => 1, // 1 = Operativo
                'usuario_crea' => $this->usuarioId(),
                'fecha_crea' => now()->toDateString(),
            ]);

            // Cargar relaciones
            $equipo->load(['tipoHardware', 'marca', 'via']);

            return $this->successResponse([
                'inventario_id' => $equipo->inventario_id,
                'maestro_id' => $equipo->maestro_id,
                'tipo_hardware' => $equipo->tipoHardware?->nombre,
                'codigo' => $equipo->codigo1 ?? $equipo->codigo2,
                'marca' => $equipo->marca?->nombre,
                'modelo' => $equipo->modelo,
                'es_nuevo' => $esNuevo,
                'movimiento_id' => $movimiento->movimiento_id,
                'via_actual' => $equipo->via?->nombre,
            ], $esNuevo ? 'Equipo registrado exitosamente' : 'Equipo actualizado exitosamente');
        }, 'Error registrando equipo');
    }

    /**
     * Obtener items de checklist de un equipo específico con respuestas
     *
     * @param int $id ID del mantenimiento
     * @param int $inventarioId ID del equipo en inventario
     * @return JsonResponse
     */
    public function getEquipoChecklistItems(int $id, int $inventarioId): JsonResponse
    {
        return $this->ejecutar(function () use ($id, $inventarioId) {
            // Verificar mantenimiento
            $mantenimiento = MantProgramacion::where('prog_id', $id)->first();
            if (!$mantenimiento) {
                return $this->notFoundResponse('Mantenimiento no encontrado');
            }

            // Verificar equipo
            $equipo = HardwareInventario::with(['tipoHardware', 'marca'])
                ->where('inventario_id', $inventarioId)
                ->where('estado', 1)
                ->first();

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

            // Obtener items de checklist configurados para el tipo de hardware
            $itemsChecklist = \App\Models\ChecklistMantenimientoVia::where('hardware_id', $equipo->maestro_id)
                ->where('estado', 1)
                ->with('itemRevision')
                ->get();

            // Obtener respuestas ya guardadas para este equipo en este mantenimiento
            $respuestas = MantChecklistRespuesta::where('prog_id', $id)
                ->where('inventario_id', $inventarioId)
                ->with('estadoEquipo')
                ->get()
                ->keyBy('id_item');

            // Obtener estados de equipo disponibles
            $estadosEquipo = \App\Models\MantEstadoEquipo::where('estado', 1)
                ->orderBy('estado_equipo_id')
                ->get()
                ->map(function ($estado) {
                    return [
                        'id' => $estado->estado_equipo_id,
                        'codigo' => $estado->codigo,
                        'nombre' => $estado->nombre,
                        'color' => $estado->color_hex,
                        'icono' => $estado->icono,
                    ];
                });

            // Construir items con respuestas
            $items = [];
            $totalItems = 0;
            $itemsRespondidos = 0;

            foreach ($itemsChecklist as $checklistItem) {
                if (!$checklistItem->itemRevision) continue;

                $totalItems++;
                $itemData = [
                    'id_item' => $checklistItem->itemRevision->id_item,
                    'nombre' => $checklistItem->itemRevision->nombre,
                    'descripcion' => $checklistItem->itemRevision->descripcion,
                    'obligatorio' => $checklistItem->itemRevision->esObligatorio(),
                    'respuesta' => null,
                ];

                // Buscar respuesta existente
                $respuesta = $respuestas->get($checklistItem->itemRevision->id_item);
                if ($respuesta) {
                    $itemsRespondidos++;
                    $itemData['respuesta'] = [
                        'respuesta_id' => $respuesta->respuesta_id,
                        'estado_equipo_id' => $respuesta->estado_equipo_id,
                        'estado_equipo_nombre' => $respuesta->estadoEquipo?->nombre,
                        'estado_equipo_color' => $respuesta->estadoEquipo?->color_hex,
                        'estado_equipo_icono' => $respuesta->estadoEquipo?->icono,
                        'observacion' => $respuesta->observacion,
                        'valor_medicion' => $respuesta->valor_medicion,
                        'fecha_registro' => $respuesta->fecha_registro?->format('Y-m-d H:i:s'),
                    ];
                }

                $items[] = $itemData;
            }

            $porcentaje = $totalItems > 0
                ? (int) round(($itemsRespondidos / $totalItems) * 100)
                : 0;

            return $this->successResponse([
                'equipo' => [
                    'inventario_id' => $equipo->inventario_id,
                    'maestro_id' => $equipo->maestro_id,
                    'tipo_hardware' => $equipo->tipoHardware?->nombre,
                    'codigo' => $equipo->codigo1 ?? $equipo->codigo2,
                    'marca' => $equipo->marca?->nombre,
                    'modelo' => $equipo->modelo,
                ],
                'estados_equipo' => $estadosEquipo,
                'items' => $items,
                'progreso' => [
                    'total' => $totalItems,
                    'respondidos' => $itemsRespondidos,
                    'porcentaje' => $porcentaje,
                ],
            ], 'Items de checklist obtenidos exitosamente');
        }, 'Error obteniendo items de checklist del equipo');
    }

    /**
     * Obtener equipos registrados en una vía
     *
     * @param int $id ID del mantenimiento
     * @param int $viaId ID de la vía
     * @return JsonResponse
     */
    public function getEquiposRegistrados(int $id, int $viaId): JsonResponse
    {
        return $this->ejecutar(function () use ($id, $viaId) {
            // Verificar que el mantenimiento existe
            $mantenimiento = MantProgramacion::where('prog_id', $id)->first();
            if (!$mantenimiento) {
                return $this->notFoundResponse('Mantenimiento no encontrado');
            }

            // Verificar que la vía existe
            $via = ViaSubcentro::where('via_id', $viaId)
                ->where('id_centro', $mantenimiento->id_centro)
                ->where('estado', 1)
                ->first();

            if (!$via) {
                return $this->notFoundResponse('Vía no encontrada');
            }

            // Obtener equipos que tienen movimientos en esta vía
            $equipos = HardwareInventario::with([
                'tipoHardware',
                'marca',
                'movimientos' => function ($q) use ($viaId) {
                    $q->where('via_id', $viaId)->orderBy('fecha', 'desc')->limit(1);
                }
            ])
                ->whereHas('movimientos', function ($q) use ($viaId) {
                    $q->where('via_id', $viaId);
                })
                ->where('estado', 1)
                ->get();

            $equiposRegistrados = [];
            foreach ($equipos as $equipo) {
                $ultimoMovimiento = $equipo->movimientos->first();

                $equiposRegistrados[] = [
                    'inventario_id' => $equipo->inventario_id,
                    'hardware_id' => $equipo->maestro_id,
                    'tipo_hardware' => $equipo->tipoHardware?->nombre,
                    'codigo' => $equipo->codigo1 ?? $equipo->codigo2,
                    'marca' => $equipo->marca?->nombre,
                    'modelo' => $equipo->modelo,
                    'ultimo_movimiento' => $ultimoMovimiento ? [
                        'fecha' => $ultimoMovimiento->fecha->format('Y-m-d H:i:s'),
                        'estado' => $ultimoMovimiento->estado_descripcion,
                    ] : null,
                ];
            }

            return $this->successResponse([
                'via' => [
                    'via_id' => $via->via_id,
                    'nombre' => $via->nombre,
                ],
                'equipos_registrados' => $equiposRegistrados
            ], 'Equipos registrados obtenidos exitosamente');
        }, 'Error obteniendo equipos registrados');
    }
}
