<?php

namespace App\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use App\Models\MantEstado;
use App\Models\MantProgramacion;
use App\Models\PeajeCentro;
use App\Models\Usuario;
use App\Models\ViaSubcentro;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class CalendarioController extends Controller
{
    /**
     * Vista principal del calendario semanal
     */
    public function index(Request $request)
    {
        // Obtener la semana actual o la solicitada
        $fechaBase = $request->get('fecha')
            ? Carbon::parse($request->get('fecha'))
            : Carbon::now();

        // Calcular inicio y fin de la semana (lunes a domingo)
        $inicioSemana = $fechaBase->copy()->startOfWeek(Carbon::MONDAY);
        $finSemana = $fechaBase->copy()->endOfWeek(Carbon::SUNDAY);

        // Filtros
        $filtros = [
            'centro_id' => $request->get('centro_id'),
            'tecnico_id' => $request->get('tecnico_id'),
            'estado_id' => $request->get('estado_id'),
        ];

        // Obtener programaciones de la semana (incluye mantenimientos que se solapan con la semana)
        $query = MantProgramacion::with(['centro', 'tecnico', 'estadoMantenimiento'])
            ->where('estado', 1) // Solo activos
            ->where(function ($q) use ($inicioSemana, $finSemana) {
                // Programaciones cuya fecha_programada está en la semana
                $q->whereBetween('fecha_programada', [$inicioSemana->format('Y-m-d'), $finSemana->format('Y-m-d')])
                  // O cuya fecha_fin está en la semana
                  ->orWhereBetween('fecha_fin', [$inicioSemana->format('Y-m-d'), $finSemana->format('Y-m-d')])
                  // O que abarcan toda la semana
                  ->orWhere(function ($inner) use ($inicioSemana, $finSemana) {
                      $inner->where('fecha_programada', '<=', $inicioSemana->format('Y-m-d'))
                            ->where('fecha_fin', '>=', $finSemana->format('Y-m-d'));
                  });
            });

        // Aplicar filtros
        if ($filtros['centro_id']) {
            $query->where('id_centro', $filtros['centro_id']);
        }
        if ($filtros['tecnico_id']) {
            $query->where('tecnico_asignado', $filtros['tecnico_id']);
        }
        if ($filtros['estado_id']) {
            $query->where('estado_id', $filtros['estado_id']);
        }

        $programaciones = $query->orderBy('fecha_programada')
            ->orderBy('id_centro')
            ->get();

        // Agrupar por día de la semana
        $semana = [];
        for ($i = 0; $i < 7; $i++) {
            $fecha = $inicioSemana->copy()->addDays($i);
            $fechaStr = $fecha->format('Y-m-d');

            $semana[$i] = [
                'fecha' => $fecha,
                'fechaStr' => $fechaStr,
                'diaNombre' => $this->getNombreDia($fecha->dayOfWeek),
                'diaNumero' => $fecha->day,
                'esHoy' => $fecha->isToday(),
                'esPasado' => $fecha->isPast() && !$fecha->isToday(),
                'programaciones' => $programaciones->filter(function ($prog) use ($fechaStr) {
                    // Mostrar en el día si la fecha cae dentro del rango de la programación
                    $fechaInicio = $prog->fecha_programada->format('Y-m-d');
                    $fechaFin = $prog->fecha_fin ? $prog->fecha_fin->format('Y-m-d') : $fechaInicio;
                    return $fechaStr >= $fechaInicio && $fechaStr <= $fechaFin;
                })->values(),
            ];
        }

        // Estadísticas de la semana
        $estadisticas = [
            'total' => $programaciones->count(),
            'completados' => $programaciones->where('estadoMantenimiento.estado_codigo', 'COMPLETADO')->count(),
            'en_proceso' => $programaciones->whereIn('estadoMantenimiento.estado_codigo', ['EN_MANTENIMIENTO', 'CAMINO_PEAJE', 'LLEGADA_PEAJE'])->count(),
            'pendientes' => $programaciones->where('estadoMantenimiento.estado_codigo', 'PROGRAMADO')->count(),
            'pendientes_aprobacion' => $programaciones->where('estadoMantenimiento.estado_codigo', 'PEND_APROBACION')->count(),
        ];

        // Datos para filtros
        $centros = PeajeCentro::where('estado', 1)->orderBy('nombre_centro')->get();
        $tecnicos = Usuario::whereHas('perfil', function ($q) {
            $q->whereHas('rol', function ($r) {
                $r->where('rol_codigo', 'TECNICOS');
            });
        })->where('usu_estado', 1)->orderBy('usu_nombre')->get();
        $estados = MantEstado::where('estado', 1)->orderBy('orden')->get();

        return view('calendario.index', compact(
            'semana',
            'inicioSemana',
            'finSemana',
            'filtros',
            'estadisticas',
            'centros',
            'tecnicos',
            'estados'
        ));
    }

    /**
     * Obtener programaciones de un día específico (AJAX)
     */
    public function getDia(Request $request)
    {
        $fecha = $request->get('fecha', now()->format('Y-m-d'));

        $programaciones = MantProgramacion::with(['centro', 'tecnico', 'estadoMantenimiento'])
            ->where('estado', 1)
            ->where(function ($q) use ($fecha) {
                // Programaciones que incluyen esta fecha
                $q->whereDate('fecha_programada', '<=', $fecha)
                  ->where(function ($inner) use ($fecha) {
                      $inner->whereDate('fecha_fin', '>=', $fecha)
                            ->orWhereNull('fecha_fin');
                  });
            })
            ->orderBy('id_centro')
            ->get();

        return response()->json([
            'fecha' => $fecha,
            'total' => $programaciones->count(),
            'programaciones' => $programaciones->map(function ($prog) {
                $fechaInicio = $prog->fecha_programada->format('Y-m-d');
                $fechaFin = $prog->fecha_fin ? $prog->fecha_fin->format('Y-m-d') : $fechaInicio;
                $esMultiDia = $fechaInicio !== $fechaFin;

                return [
                    'id' => $prog->prog_id,
                    'centro' => $prog->centro->nombre_centro ?? 'N/A',
                    'tecnico' => $prog->tecnico ? $prog->tecnico->usu_nombre . ' ' . $prog->tecnico->usu_apellido : 'Sin asignar',
                    'tecnico_iniciales' => $prog->tecnico ? strtoupper(substr($prog->tecnico->usu_nombre, 0, 1) . substr($prog->tecnico->usu_apellido ?? '', 0, 1)) : '??',
                    'estado' => $prog->estadoMantenimiento->estado_nombre ?? 'Programado',
                    'estado_codigo' => $prog->estadoMantenimiento->estado_codigo ?? 'PROGRAMADO',
                    'estado_color' => $prog->estadoMantenimiento->color_hex ?? '#9E9E9E',
                    'fecha_inicio' => $fechaInicio,
                    'fecha_fin' => $fechaFin,
                    'es_multi_dia' => $esMultiDia,
                    'observaciones' => $prog->observaciones,
                ];
            }),
        ]);
    }

    /**
     * Formulario para crear nueva programación
     */
    public function create(Request $request)
    {
        $fecha = $request->get('fecha', now()->format('Y-m-d'));

        $centros = PeajeCentro::where('estado', 1)
            ->where('mantenimiento', 1)
            ->orderBy('nombre_centro')
            ->get();

        $tecnicos = Usuario::whereHas('perfil', function ($q) {
            $q->whereHas('rol', function ($r) {
                $r->where('rol_codigo', 'TECNICOS');
            });
        })->where('usu_estado', 1)->orderBy('usu_nombre')->get();

        return view('calendario.create', compact('fecha', 'centros', 'tecnicos'));
    }

    /**
     * Obtener vías de un centro (AJAX)
     */
    public function getVias(int $centroId)
    {
        $vias = ViaSubcentro::where('id_centro', $centroId)
            ->where('estado', 1)
            ->orderBy('nombre')
            ->get(['via_id', 'nombre']);

        return response()->json($vias);
    }

    /**
     * Guardar nueva programación
     */
    public function store(Request $request)
    {
        $request->validate([
            'id_centro' => 'required|exists:peaje_centro,id_centro',
            'anio' => 'required|integer|min:2020|max:2100',
            'mes' => 'required|integer|min:1|max:12',
            'fecha_programada' => 'required|date|after_or_equal:today',
            'fecha_fin' => 'nullable|date|after_or_equal:fecha_programada',
            'tecnico_asignado' => 'required|exists:usuarios,usu_id',
            'observaciones' => 'nullable|string|max:500',
        ], [
            'id_centro.required' => 'Seleccione un centro/peaje',
            'anio.required' => 'Seleccione el año',
            'mes.required' => 'Seleccione el período (mes)',
            'fecha_programada.required' => 'Seleccione una fecha de inicio',
            'fecha_programada.after_or_equal' => 'La fecha de inicio no puede ser anterior a hoy',
            'fecha_fin.after_or_equal' => 'La fecha de fin debe ser igual o posterior a la fecha de inicio',
            'tecnico_asignado.required' => 'Seleccione un técnico',
        ]);

        // La fecha_fin por defecto es igual a fecha_programada si no se especifica
        $fechaFin = $request->fecha_fin ?: $request->fecha_programada;

        // Verificar si ya existe una programación para ese centro en ese rango de fechas
        $existe = MantProgramacion::where('id_centro', $request->id_centro)
            ->where('estado', 1)
            ->where(function ($query) use ($request, $fechaFin) {
                // Verifica si hay solapamiento de fechas
                $query->where(function ($q) use ($request, $fechaFin) {
                    $q->whereBetween('fecha_programada', [$request->fecha_programada, $fechaFin])
                      ->orWhereBetween('fecha_fin', [$request->fecha_programada, $fechaFin])
                      ->orWhere(function ($inner) use ($request, $fechaFin) {
                          $inner->where('fecha_programada', '<=', $request->fecha_programada)
                                ->where('fecha_fin', '>=', $fechaFin);
                      });
                });
            })
            ->exists();

        if ($existe) {
            return back()->withErrors(['duplicado' => 'Ya existe una programación para este peaje en las fechas seleccionadas'])->withInput();
        }

        // Obtener estado inicial
        $estadoProgramado = MantEstado::where('estado_codigo', 'PROGRAMADO')->first();

        $programacion = MantProgramacion::create([
            'id_centro' => $request->id_centro,
            'anio' => $request->anio,
            'mes' => $request->mes,
            'fecha_programada' => $request->fecha_programada,
            'fecha_fin' => $fechaFin,
            'tecnico_asignado' => $request->tecnico_asignado,
            'estado_id' => $estadoProgramado->estado_id,
            'observaciones' => $request->observaciones,
            'estado' => 1,
            'usuario_crea' => auth()->id(),
            'fecha_crea' => now(),
        ]);

        return redirect()->route('web.calendario.index', ['fecha' => $request->fecha_programada])
            ->with('success', 'Mantenimiento programado correctamente');
    }

    /**
     * Reprogramar mantenimiento
     */
    public function reprogramar(Request $request, int $id)
    {
        $request->validate([
            'nueva_fecha' => 'required|date|after_or_equal:today',
            'motivo' => 'required|string|max:500',
        ]);

        $programacion = MantProgramacion::findOrFail($id);

        $programacion->update([
            'fecha_reprogramacion_origen' => $programacion->fecha_programada,
            'fecha_programada' => $request->nueva_fecha,
            'motivo_reprogramacion' => $request->motivo,
            'usuario_modifica' => auth()->id(),
            'fecha_modifica' => now(),
        ]);

        return redirect()->route('web.calendario.index', ['fecha' => $request->nueva_fecha])
            ->with('success', 'Mantenimiento reprogramado correctamente');
    }

    /**
     * Cancelar mantenimiento
     */
    public function cancelar(Request $request, int $id)
    {
        $request->validate([
            'motivo' => 'required|string|max:500',
        ]);

        $programacion = MantProgramacion::findOrFail($id);
        $estadoCancelado = MantEstado::where('estado_codigo', 'CANCELADO')->first();

        $programacion->update([
            'estado_id' => $estadoCancelado->estado_id,
            'motivo_cancelacion' => $request->motivo,
            'usuario_cancela' => auth()->id(),
            'fecha_cancela' => now(),
        ]);

        return back()->with('success', 'Mantenimiento cancelado');
    }

    /**
     * Obtener nombre del día
     */
    private function getNombreDia(int $dayOfWeek): string
    {
        $dias = ['Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb'];
        return $dias[$dayOfWeek];
    }
}
