<?php

namespace App\Http\Controllers;

use App\Models\Area;
use App\Models\EstadoOrden;
use App\Models\Equipo;
use App\Models\OrdenTrabajo;
use App\Models\OrdenLog;
use App\Models\OrdenItem;
use App\Models\OrdenFoto;
use App\Models\OrdenCosto;
use App\Models\PlanMantenimiento;
use App\Models\Prioridad;
use App\Models\Repuesto;
use App\Models\MovimientoInventario;
use App\Models\User;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Intervention\Image\Laravel\Facades\Image;

class OrdenTrabajoController extends Controller
{
    public function index(Request $r)
    {
        $clase = $r->get('clase');
        $q = OrdenTrabajo::with(['equipo','area','estado','prioridad','responsable']);
        if ($clase) $q->where('clase', $clase);
        if ($busqueda = trim((string)$r->get('q',''))) {
            $q->where(fn($w) => $w->where('codigo','like',"%$busqueda%")
                ->orWhereHas('equipo', fn($e) => $e->where('nombre','like',"%$busqueda%")));
        }
        if ($estado = $r->integer('estado_id')) $q->where('estado_id', $estado);
        if ($area = $r->integer('area_id')) $q->where('area_id', $area);
        if ($desde = $r->date('desde')) $q->whereDate('fecha_programada','>=',$desde);
        if ($hasta = $r->date('hasta')) $q->whereDate('fecha_programada','<=',$hasta);
        $perPage = min(500, max(10, (int) $r->get('per_page', 100)));
        $registros = $q->orderByDesc('fecha_programada')->paginate($perPage)->withQueryString();
        $estados = EstadoOrden::where('activo',1)->orderBy('orden')->get();
        $areas = Area::where('activo',1)->orderBy('nombre')->get();
        return view('ordenes.index', compact('registros','clase','busqueda','estados','areas'));
    }

    public function create(Request $r)
    {
        $orden = new OrdenTrabajo([
            'clase' => $r->get('clase','correctivo'),
            'fecha_programada' => Carbon::today()->toDateString(),
        ]);
        return view('ordenes.form', $this->datosFormulario($orden));
    }

    public function store(Request $r)
    {
        $datos = $this->validar($r);
        $datos['codigo'] = $this->generarCodigo($datos['clase']);
        $datos['creado_por'] = auth()->id();
        if (empty($datos['estado_id'])) {
            $datos['estado_id'] = EstadoOrden::where('codigo','PEN')->value('id');
        }
        $orden = OrdenTrabajo::create($datos);
        OrdenLog::create([
            'orden_id' => $orden->id, 'usuario_id' => auth()->id(),
            'accion' => 'creacion', 'estado_nuevo' => optional($orden->estado)->codigo,
        ]);

        // Si la OT viene de un plan, copiar los ítems del plan al checklist
        if ($orden->plan_id) {
            $this->poblarDesdePlanInterno($orden);
        }

        return redirect()->route('ordenes.show', $orden)->with('exito','Orden creada.');
    }

    /**
     * Copia los ítems del plan asociado al checklist de la OT.
     * No duplica: solo agrega los que falten.
     */
    protected function poblarDesdePlanInterno(OrdenTrabajo $orden): int
    {
        if (!$orden->plan_id) return 0;
        $existentes = OrdenItem::where('orden_id', $orden->id)
            ->whereNotNull('plan_item_id')->pluck('plan_item_id')->all();
        $items = \App\Models\PlanItem::where('plan_id', $orden->plan_id)
            ->where('activo', 1)
            ->whereNotIn('id', $existentes)
            ->orderBy('numero_item')->get();
        $creados = 0;
        foreach ($items as $pi) {
            OrdenItem::create([
                'orden_id' => $orden->id,
                'plan_item_id' => $pi->id,
                'numero_item' => $pi->numero_item ?: ($creados + count($existentes) + 1),
                'descripcion' => $pi->descripcion,
                'estado_item' => 'pendiente',
                'lila_l_limpieza' => $pi->lila_l_limpieza,
                'lila_i_inspeccion' => $pi->lila_i_inspeccion,
                'lila_l_lubricacion' => $pi->lila_l_lubricacion,
                'lila_a_ajuste' => $pi->lila_a_ajuste,
            ]);
            $creados++;
        }
        return $creados;
    }

    public function poblarDesdePlan(OrdenTrabajo $orden)
    {
        if (!$orden->plan_id) return back()->with('error','Esta orden no está asociada a un plan.');
        $n = $this->poblarDesdePlanInterno($orden);
        OrdenLog::create([
            'orden_id' => $orden->id, 'usuario_id' => auth()->id(),
            'accion' => 'poblar_checklist', 'detalle' => "Se cargaron {$n} ítems desde el plan.",
        ]);
        return back()->with('exito', "Se agregaron {$n} ítems al checklist desde el plan.");
    }

    public function itemStore(Request $r, OrdenTrabajo $orden)
    {
        $datos = $r->validate([
            'descripcion' => 'required|string|max:500',
            'numero_item' => 'nullable|integer',
            'lectura_condicion' => 'nullable|string|max:100',
        ]);
        $datos['orden_id'] = $orden->id;
        $datos['estado_item'] = 'pendiente';
        $datos['numero_item'] = ($datos['numero_item'] ?? null)
            ?: ((int) OrdenItem::where('orden_id',$orden->id)->max('numero_item') + 1);
        foreach (['lila_l_limpieza','lila_i_inspeccion','lila_l_lubricacion','lila_a_ajuste'] as $f) {
            $datos[$f] = $r->boolean($f);
        }
        OrdenItem::create($datos);
        return back()->with('exito','Ítem agregado al checklist.');
    }

    public function itemDestroy(OrdenTrabajo $orden, OrdenItem $item)
    {
        abort_unless($item->orden_id === $orden->id, 404);
        $item->delete();
        return back()->with('exito','Ítem eliminado.');
    }

    public function show(OrdenTrabajo $orden)
    {
        $orden->load(['plan','equipo.area','estado','prioridad','responsable','responsables','creador',
            'items.planItem','fotos','logs.usuario','costos','archivos','aprobador','cerrador']);
        $estados = EstadoOrden::where('activo',1)->orderBy('orden')->get();
        $repuestos = Repuesto::where('activo',1)->orderBy('nombre')->get();
        return view('ordenes.show', compact('orden','estados','repuestos'));
    }

    public function edit(OrdenTrabajo $orden)
    {
        return view('ordenes.form', $this->datosFormulario($orden));
    }

    public function update(Request $r, OrdenTrabajo $orden)
    {
        $estadoAnterior = optional($orden->estado)->codigo;
        $orden->update($this->validar($r, $orden->id));
        if (optional($orden->fresh()->estado)->codigo !== $estadoAnterior) {
            OrdenLog::create([
                'orden_id' => $orden->id, 'usuario_id' => auth()->id(),
                'accion' => 'cambio_estado', 'estado_anterior' => $estadoAnterior,
                'estado_nuevo' => optional($orden->fresh()->estado)->codigo,
            ]);
        }
        return back()->with('exito','Orden actualizada.');
    }

    public function destroy(OrdenTrabajo $orden)
    {
        // Bloquear si la OT ya fue ejecutada o aprobada
        $codigoEstado = optional($orden->estado)->codigo;
        if (in_array($codigoEstado, ['EJE', 'APR'])) {
            return back()->with('error', "No se puede eliminar la OT {$orden->codigo} porque está {$orden->estado->nombre}. Las OT ejecutadas o aprobadas no se pueden borrar.");
        }
        $orden->delete();
        return redirect()->route('ordenes.index')->with('exito','Orden eliminada.');
    }

    /**
     * Eliminación múltiple. Recibe ids[] y borra solo las que NO estén ejecutadas/aprobadas.
     */
    public function eliminarMultiples(Request $r)
    {
        $r->validate([
            'ids' => 'required|array|min:1',
            'ids.*' => 'integer|exists:ordenes_trabajo,id',
        ]);

        $ordenes = OrdenTrabajo::with('estado')->whereIn('id', $r->ids)->get();
        $eliminadas = 0;
        $bloqueadas = [];

        foreach ($ordenes as $orden) {
            $codigo = optional($orden->estado)->codigo;
            if (in_array($codigo, ['EJE', 'APR'])) {
                $bloqueadas[] = $orden->codigo . ' (' . $orden->estado->nombre . ')';
                continue;
            }
            $orden->delete();
            $eliminadas++;
        }

        $msg = "Eliminadas: {$eliminadas}.";
        if (!empty($bloqueadas)) {
            $lista = implode(', ', array_slice($bloqueadas, 0, 5));
            $extra = count($bloqueadas) > 5 ? ' y ' . (count($bloqueadas) - 5) . ' más' : '';
            $msg .= " Bloqueadas (no se pueden eliminar OT ejecutadas/aprobadas): {$lista}{$extra}.";
            return back()->with('error', $msg);
        }
        return back()->with('exito', $msg);
    }

    // === Cambios de estado ===
    public function cambiarEstado(Request $r, OrdenTrabajo $orden)
    {
        $r->validate(['estado_id' => 'required|exists:estados_orden,id']);
        $estadoAnterior = optional($orden->estado)->codigo;
        $estadoNuevo = EstadoOrden::find($r->estado_id);
        $orden->estado_id = $estadoNuevo->id;
        if ($estadoNuevo->codigo === 'EPR' && !$orden->fecha_inicio) $orden->fecha_inicio = now();
        if ($estadoNuevo->codigo === 'EJE') {
            $orden->fecha_cierre = now();
            $orden->cerrado_por = auth()->id();
            // Si es una OT por horas, actualizar el "último PM" del equipo
            if ($orden->pm_tipo && $orden->horometro_fin && $orden->equipo_id) {
                $col = 'ultimo_pm_' . $orden->pm_tipo;
                $equipo = \App\Models\Equipo::find($orden->equipo_id);
                if ($equipo && in_array($col, ['ultimo_pm_360','ultimo_pm_720','ultimo_pm_4320','ultimo_pm_8640'])) {
                    $equipo->$col = $orden->horometro_fin;
                    $equipo->save();
                }
            }
        }
        if ($estadoNuevo->codigo === 'APR') {
            $orden->fecha_aprobacion = now();
            $orden->aprobado_por = auth()->id();
        }
        $orden->save();
        OrdenLog::create([
            'orden_id' => $orden->id, 'usuario_id' => auth()->id(),
            'accion' => 'cambio_estado', 'estado_anterior' => $estadoAnterior,
            'estado_nuevo' => $estadoNuevo->codigo, 'detalle' => $r->input('comentario'),
        ]);
        return back()->with('exito','Estado actualizado.');
    }

    public function firmar(Request $r, OrdenTrabajo $orden)
    {
        $r->validate(['clave_firma' => 'required|string', 'tipo' => 'required|in:responsable,supervisor']);
        $usuario = auth()->user();
        if (!$usuario->verificarClaveFirma($r->clave_firma)) {
            return back()->with('error','Clave de firma inválida.');
        }
        $campo = $r->tipo === 'supervisor' ? 'firma_supervisor' : 'firma_responsable';
        $sello = now()->format('d/m/Y H:i');
        $orden->$campo = $usuario->firma_imagen
            ? 'IMG:' . $usuario->firma_imagen . '|' . $usuario->nombre_completo . '|' . $sello
            : 'TXT:' . $usuario->nombre_completo . '|' . $sello;
        $orden->save();
        OrdenLog::create([
            'orden_id' => $orden->id, 'usuario_id' => $usuario->id,
            'accion' => 'firma_' . $r->tipo,
        ]);
        return back()->with('exito','Orden firmada.');
    }

    // === Costos ===
    public function agregarCosto(Request $r, OrdenTrabajo $orden)
    {
        $datos = $r->validate([
            'concepto' => 'required|string|max:200',
            'tipo' => 'required|in:mano_obra,repuesto,otro',
            'cantidad' => 'required|numeric|min:0',
            'costo_unitario' => 'required|numeric|min:0',
            'repuesto_id' => 'nullable|exists:repuestos,id',
        ]);
        $datos['orden_id'] = $orden->id;
        $datos['costo_total'] = $datos['cantidad'] * $datos['costo_unitario'];
        $costo = OrdenCosto::create($datos);
        if ($datos['tipo'] === 'repuesto' && $datos['repuesto_id']) {
            MovimientoInventario::create([
                'repuesto_id' => $datos['repuesto_id'],
                'orden_id' => $orden->id,
                'tipo' => 'salida',
                'cantidad' => $datos['cantidad'],
                'costo_unitario' => $datos['costo_unitario'],
                'costo_total' => $costo->costo_total,
                'motivo' => 'OT ' . $orden->codigo,
                'usuario_id' => auth()->id(),
            ]);
            DB::table('repuestos')->where('id', $datos['repuesto_id'])->decrement('stock', $datos['cantidad']);
        }
        $this->recalcularCostos($orden);
        return back()->with('exito','Costo agregado.');
    }

    public function eliminarCosto(OrdenTrabajo $orden, OrdenCosto $costo)
    {
        abort_unless($costo->orden_id === $orden->id, 404);
        $costo->delete();
        $this->recalcularCostos($orden);
        return back()->with('exito','Costo eliminado.');
    }

    private function recalcularCostos(OrdenTrabajo $orden): void
    {
        $costos = $orden->costos()->get();
        $orden->costo_mano_obra = $costos->where('tipo','mano_obra')->sum('costo_total');
        $orden->costo_repuestos = $costos->where('tipo','repuesto')->sum('costo_total');
        $orden->costo_otros = $costos->where('tipo','otro')->sum('costo_total');
        $orden->costo_total = $orden->costo_mano_obra + $orden->costo_repuestos + $orden->costo_otros;
        $orden->save();
    }

    // === Items / checklist ===
    public function actualizarItem(Request $r, OrdenTrabajo $orden, OrdenItem $item)
    {
        abort_unless($item->orden_id === $orden->id, 404);
        $datos = $r->validate([
            'estado_item' => 'required|in:pendiente,realizado,no_aplica,no_realizado',
            'lectura_condicion' => 'nullable|string|max:100',
            'observaciones' => 'nullable|string',
        ]);
        foreach (['lila_l_limpieza','lila_i_inspeccion','lila_l_lubricacion','lila_a_ajuste'] as $f) {
            $datos[$f] = $r->boolean($f);
        }
        if ($datos['estado_item'] === 'realizado') {
            $datos['ejecutado_en'] = now();
            $datos['ejecutado_por'] = auth()->id();
        }
        $item->update($datos);
        return back()->with('exito','Ítem actualizado.');
    }

    // === Fotos ===
    public function subirFoto(Request $r, OrdenTrabajo $orden)
    {
        $r->validate([
            'foto' => 'required|image|max:8192',
            'tipo' => 'nullable|in:antes,despues,evidencia,placa,manual,firma,otro',
            'descripcion' => 'nullable|string|max:255',
            'orden_item_id' => 'nullable|exists:ordenes_items,id',
        ]);
        $archivo = $r->file('foto');
        $maxKb = (int) \App\Models\Configuracion::obtener('max_tamano_foto_kb', 1024);
        $maxAncho = (int) \App\Models\Configuracion::obtener('ancho_foto_max', 1600);
        $contenido = file_get_contents($archivo->getRealPath());
        try {
            $img = Image::read($contenido);
            if ($img->width() > $maxAncho) $img->scaleDown(width: $maxAncho);
            $contenido = (string) $img->toJpeg(80);
            $ext = 'jpg';
        } catch (\Throwable $e) {
            $ext = $archivo->getClientOriginalExtension() ?: 'bin';
        }
        $nombre = 'ordenes/' . $orden->id . '/' . uniqid('foto_') . '.' . $ext;
        Storage::disk('public')->put($nombre, $contenido);
        OrdenFoto::create([
            'orden_id' => $orden->id,
            'orden_item_id' => $r->input('orden_item_id'),
            'ruta' => $nombre,
            'tipo' => $r->input('tipo','evidencia'),
            'descripcion' => $r->input('descripcion'),
            'subido_por' => auth()->id(),
        ]);
        return back()->with('exito','Foto cargada.');
    }

    public function eliminarFoto(OrdenTrabajo $orden, OrdenFoto $foto)
    {
        abort_unless($foto->orden_id === $orden->id, 404);
        Storage::disk('public')->delete($foto->ruta);
        $foto->delete();
        return back()->with('exito','Foto eliminada.');
    }

    public function pdf(OrdenTrabajo $orden)
    {
        $orden->load(['equipo.area','area','sistema','estado','prioridad','responsable','creador',
            'items','fotos.subidoPor','costos','logs.usuario']);
        $pdf = Pdf::loadView('ordenes.pdf', ['orden' => $orden])->setPaper('a4');
        return $pdf->stream("OT_{$orden->codigo}.pdf");
    }

    private function generarCodigo(string $clase): string
    {
        $prefijo = $clase === 'correctivo'
            ? \App\Models\Configuracion::obtener('prefijo_orden_correctiva', 'OTC')
            : \App\Models\Configuracion::obtener('prefijo_orden_preventiva', 'OTP');
        $anio = now()->year;
        $count = OrdenTrabajo::where('clase',$clase)->whereYear('created_at',$anio)->count() + 1;
        return $prefijo . '-' . $anio . '-' . str_pad((string)$count, 5, '0', STR_PAD_LEFT);
    }

    private function validar(Request $r, ?int $id = null): array
    {
        $datos = $r->validate([
            'clase' => 'required|in:preventivo,correctivo',
            'plan_id' => 'nullable|exists:planes_mantenimiento,id',
            'area_id' => 'nullable|exists:areas,id',
            'sistema_id' => 'nullable|exists:sistemas,id',
            'equipo_id' => 'required|exists:equipos,id',
            'estado_id' => 'nullable|exists:estados_orden,id',
            'prioridad_id' => 'nullable|exists:prioridades,id',
            'responsable_id' => 'nullable|exists:usuarios,id',
            'fecha_programada' => 'nullable|date',
            'fecha_vencimiento' => 'nullable|date',
            'horometro_inicio' => 'nullable|numeric|min:0',
            'horometro_fin' => 'nullable|numeric|min:0',
            'descripcion' => 'nullable|string',
            'observaciones' => 'nullable|string',
            'observaciones_cierre' => 'nullable|string',
        ]);
        return $datos;
    }

    private function datosFormulario(OrdenTrabajo $orden): array
    {
        return [
            'orden' => $orden,
            'planes' => PlanMantenimiento::with(['items' => fn($q) => $q->orderBy('numero_item')->limit(1)])
                ->where('activo',1)->orderBy('codigo')->get(),
            'areas' => Area::where('activo',1)->orderBy('nombre')->get(),
            'equipos' => Equipo::where('activo',1)->orderBy('nombre')->get(),
            'estados' => EstadoOrden::where('activo',1)->orderBy('orden')->get(),
            'prioridades' => Prioridad::where('activo',1)->orderBy('nivel')->get(),
            'usuarios' => User::where('activo',1)->orderBy('nombres')->get(),
        ];
    }
}
