"use client";

import { useEffect, useMemo, useState } from "react";
import Link from "next/link";
import { CalendarDays, Loader2, RefreshCw } from "lucide-react";
import Button from "@/components/ui/Button";
import { listPedidos } from "@/lib/pb/pedidos";
import { dateInputValue } from "@/lib/format";
import { inferEtapaProduccion, pipelineCalendarClass, PIPELINE_LABELS, PIPELINE_COLORS } from "@/lib/pedidos/pipeline";
import type { Pedido } from "@/lib/types/pedido";
import { money } from "@/lib/format";
import { normalizeFotos } from "@/components/pedidos/PhotoCapture";
import { fileUrl } from "@/lib/pocketbase";

type CalendarPedido = Pedido & {
  fecha_entrega_hasta?: string;
  fecha_entrega_fin?: string;
  fecha_entrega_extendida?: string;
  fecha_entrega_estimada_hasta?: string;
};

interface DeliveryEvent {
  id: string;
  title: string;
  cliente: string;
  start: Date;
  end: Date;
  pedido: CalendarPedido;
}

const MONTH = new Intl.DateTimeFormat("es-AR", { month: "long", year: "numeric" });
const WEEK_DAYS = ["Lun", "Mar", "Mié", "Jue", "Vie", "Sáb", "Dom"];

export default function CalendarioPage() {
  const [pedidos, setPedidos] = useState<CalendarPedido[]>([]);
  const [loading, setLoading] = useState(true);
  const [err, setErr] = useState("");
  const [hoveredEvent, setHoveredEvent] = useState<{
    event: DeliveryEvent;
    x: number;
    y: number;
  } | null>(null);

  async function load() {
    setLoading(true);
    setErr("");
    try {
      const res = await listPedidos({ perPage: 500 });
      setPedidos(
        res.items
          .filter((pedido) => pedido.estado_pedido !== "cancelado" && pedido.fecha_entrega_estimada)
          .map((pedido) => pedido as CalendarPedido),
      );
    } catch (e) {
      setErr((e as Error).message || "No se pudo cargar el calendario");
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    load();
  }, []);

  const months = useMemo(() => {
    const today = new Date();
    return [-1, 0, 1].map((offset) => new Date(today.getFullYear(), today.getMonth() + offset, 1));
  }, []);

  const events = useMemo(() => pedidos.map(toDeliveryEvent).filter(Boolean) as DeliveryEvent[], [pedidos]);

  // Position adjustments to prevent tooltip from overflowing the viewport
  const tooltipWidth = 260;
  const tooltipHeight = 280;
  let tooltipLeft = 0;
  let tooltipTop = 0;

  if (hoveredEvent) {
    const viewportW = typeof window !== "undefined" ? window.innerWidth : 1200;
    const viewportH = typeof window !== "undefined" ? window.innerHeight : 800;

    tooltipLeft = hoveredEvent.x + 15;
    tooltipTop = hoveredEvent.y + 15;

    if (tooltipLeft + tooltipWidth > viewportW) {
      tooltipLeft = hoveredEvent.x - tooltipWidth - 15;
    }
    if (tooltipTop + tooltipHeight > viewportH) {
      tooltipTop = hoveredEvent.y - tooltipHeight - 15;
    }
    if (tooltipLeft < 0) tooltipLeft = 10;
    if (tooltipTop < 0) tooltipTop = 10;
  }

  return (
    <div className="max-w-[1600px] space-y-4">
      <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
        <div>
          <h1 className="flex items-center gap-2 text-2xl font-extrabold text-ink">
            <CalendarDays className="h-6 w-6 text-brand-dark" /> Calendario de entregas
          </h1>
          <p className="text-sm text-ink-soft">
            Pedidos con fecha de entrega, con barras cuando la entrega ocupa varios días.
          </p>
        </div>
        <Button type="button" variant="secondary" onClick={load} loading={loading}>
          <RefreshCw size={16} /> Actualizar
        </Button>
      </div>

      {err && <div className="rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-bad">{err}</div>}

      {loading ? (
        <div className="grid place-items-center py-20 text-faint">
          <Loader2 className="h-6 w-6 animate-spin" />
        </div>
      ) : (
        <div className="flex flex-col gap-4">
          {months.map((month) => (
            <MonthPanel
              key={month.toISOString()}
              month={month}
              events={events}
              onHoverEvent={(event, x, y) => setHoveredEvent({ event, x, y })}
              onHoverMove={(x, y) => setHoveredEvent((prev) => (prev ? { ...prev, x, y } : null))}
              onHoverLeave={() => setHoveredEvent(null)}
            />
          ))}
        </div>
      )}

      {/* Custom floating tooltip */}
      {hoveredEvent && (() => {
        const event = hoveredEvent.event;
        const stage = event.pedido.etapa_produccion || inferEtapaProduccion(event.pedido);
        const stageLabel = PIPELINE_LABELS[stage];
        const stageColor = PIPELINE_COLORS[stage]?.labelClass || "bg-slate-100 text-slate-800";
        
        const isSameDay = event.start.toDateString() === event.end.toDateString();
        const formattedStart = event.start.toLocaleDateString("es-AR", { day: "numeric", month: "short" });
        const formattedEnd = event.end.toLocaleDateString("es-AR", { day: "numeric", month: "short" });
        const dateRangeStr = isSameDay ? formattedStart : `${formattedStart} al ${formattedEnd}`;

        return (
          <div
            className="fixed z-50 pointer-events-none rounded-xl border border-line bg-surface p-3 shadow-xl max-w-[280px] w-64 space-y-3 text-xs"
            style={{
              left: `${tooltipLeft}px`,
              top: `${tooltipTop}px`,
            }}
          >
            <div className="flex items-start justify-between gap-2">
              <div className="min-w-0">
                <h3 className="font-extrabold text-sm text-ink truncate">{event.title}</h3>
                <p className="font-semibold text-ink-soft truncate">{event.cliente}</p>
              </div>
              <span className={`rounded-full px-2 py-0.5 text-[10px] font-bold border shrink-0 ${stageColor}`}>
                {stageLabel}
              </span>
            </div>

            {/* Dates & Balance */}
            <div className="text-[10px] text-faint flex flex-col gap-0.5 border-t border-line/40 pt-2">
              <div>
                <span className="font-bold text-ink-soft">Entrega: </span>
                <span>{dateRangeStr}</span>
              </div>
              {event.pedido.saldo !== undefined && event.pedido.saldo > 0 ? (
                <div>
                  <span className="font-bold text-bad">Saldo: </span>
                  <span className="font-semibold text-bad">{money(event.pedido.saldo)}</span>
                </div>
              ) : (
                <div>
                  <span className="font-bold text-good">Pagado</span>
                </div>
              )}
            </div>

            {/* Badges */}
            {(event.pedido.hay_que_medir || event.pedido.hay_que_enviar || event.pedido.hay_que_instalar || event.pedido.requiere_pintura) && (
              <div className="flex flex-wrap gap-1 border-t border-line/40 pt-2">
                {event.pedido.hay_que_medir && <span className="rounded bg-violet-100 text-violet-800 border border-violet-200 px-1 py-0.5 text-[9px] font-bold">Medir</span>}
                {event.pedido.hay_que_enviar && <span className="rounded bg-amber-100 text-amber-800 border border-amber-200 px-1 py-0.5 text-[9px] font-bold">Enviar</span>}
                {event.pedido.hay_que_instalar && <span className="rounded bg-red-100 text-red-800 border border-red-200 px-1 py-0.5 text-[9px] font-bold">Instalar</span>}
                {event.pedido.requiere_pintura && <span className="rounded bg-purple-100 text-purple-800 border border-purple-200 px-1 py-0.5 text-[9px] font-bold">Pintar</span>}
              </div>
            )}

            {/* Foto del croquis */}
            {(() => {
              const fotos = normalizeFotos(event.pedido.dibujo_png);
              if (!fotos.length) return null;
              return (
                <div className="border-t border-line/40 pt-2">
                  <div className="text-[9px] font-bold text-faint mb-1.5 uppercase tracking-wide">
                    {`Foto del croquis${fotos.length > 1 ? ` (${fotos.length})` : ""}`}
                  </div>
                  {/* eslint-disable-next-line @next/next/no-img-element */}
                  <img
                    src={fileUrl(event.pedido, fotos[0], "400x0")}
                    alt="Croquis del pedido"
                    className="max-h-[160px] w-full rounded-lg border border-line bg-canvas object-contain"
                  />
                </div>
              );
            })()}
          </div>
        );
      })()}
    </div>
  );
}

function MonthPanel({
  month,
  events,
  onHoverEvent,
  onHoverMove,
  onHoverLeave,
}: {
  month: Date;
  events: DeliveryEvent[];
  onHoverEvent: (event: DeliveryEvent, x: number, y: number) => void;
  onHoverMove: (x: number, y: number) => void;
  onHoverLeave: () => void;
}) {
  const weeks = useMemo(() => monthWeeks(month), [month]);
  const todayKey = dayKey(startOfDay(new Date()));
  const monthIndex = month.getMonth();

  return (
    <section className="rounded-xl border border-line bg-surface p-3">
      <div className="mb-3 flex items-center justify-between gap-2">
        <h2 className="capitalize text-base font-extrabold text-ink">{MONTH.format(month)}</h2>
        <span className="rounded-full bg-canvas px-2 py-0.5 text-xs font-bold text-faint">
          {events.filter((event) => eventOverlapsRange(event, weeks[0][0], weeks.at(-1)?.[6] || weeks[0][6])).length}
        </span>
      </div>
      <div className="grid grid-cols-7 gap-px overflow-hidden rounded-lg border border-line bg-line text-center">
        {WEEK_DAYS.map((day) => (
          <div key={day} className="bg-canvas px-1 py-2 text-[11px] font-extrabold uppercase text-faint">
            {day}
          </div>
        ))}
      </div>
      <div className="mt-2 space-y-2">
        {weeks.map((week) => {
          const weekEvents = events
            .filter((event) => eventOverlapsRange(event, week[0], week[6]))
            .sort((a, b) => a.start.getTime() - b.start.getTime() || b.end.getTime() - a.end.getTime());

          return (
            <div key={week.map(dayKey).join("-")} className="rounded-lg border border-line bg-canvas p-2">
              <div className="grid grid-cols-7 gap-1">
                {week.map((day) => {
                  const isCurrentMonth = day.getMonth() === monthIndex;
                  const isToday = dayKey(day) === todayKey;
                  return (
                    <div
                      key={dayKey(day)}
                      className={[
                        "h-7 rounded-md px-1 text-right text-xs font-bold",
                        isCurrentMonth ? "text-ink" : "text-faint/50",
                        isToday ? "bg-brand text-white" : "bg-surface",
                      ].join(" ")}
                    >
                      {day.getDate()}
                    </div>
                  );
                })}
              </div>
              <div className="mt-1 grid grid-cols-7 gap-1">
                {weekEvents.length === 0 ? (
                  <div className="col-span-7 h-6 rounded-md bg-surface/60" />
                ) : (
                  weekEvents.map((event) => {
                    const startCol = Math.max(1, daysBetween(week[0], maxDate(event.start, week[0])) + 1);
                    const endCol = Math.min(7, daysBetween(week[0], minDate(event.end, week[6])) + 1);
                    return (
                      <Link
                        key={`${event.id}-${dayKey(week[0])}`}
                        href={`/pedidos/${event.id}`}
                        className={`min-w-0 rounded-md px-2 py-0.5 text-[11px] font-bold ${pipelineCalendarClass(event.pedido.etapa_produccion || inferEtapaProduccion(event.pedido))}`}
                        style={{ gridColumn: `${startCol} / ${endCol + 1}` }}
                        onMouseEnter={(e) => onHoverEvent(event, e.clientX, e.clientY)}
                        onMouseMove={(e) => onHoverMove(e.clientX, e.clientY)}
                        onMouseLeave={onHoverLeave}
                      >
                        <div className="truncate">
                          <span>{event.title}</span>
                          <span className="ml-1 font-semibold opacity-85">{event.cliente}</span>
                        </div>
                        {(event.pedido.hay_que_medir || event.pedido.hay_que_enviar || event.pedido.hay_que_instalar) && (
                          <span className="mt-0.5 flex flex-wrap gap-1">
                            {event.pedido.hay_que_medir && <span className="rounded bg-white/55 px-1 text-[9px]">Medir</span>}
                            {event.pedido.hay_que_enviar && <span className="rounded bg-white/55 px-1 text-[9px]">Enviar</span>}
                            {event.pedido.hay_que_instalar && <span className="rounded bg-white/55 px-1 text-[9px]">Instalar</span>}
                          </span>
                        )}
                      </Link>
                    );
                  })
                )}
              </div>
            </div>
          );
        })}
      </div>
    </section>
  );
}

function toDeliveryEvent(pedido: CalendarPedido): DeliveryEvent | null {
  const start = parseDate(pedido.fecha_entrega_estimada);
  if (!start) return null;
  const end =
    parseDate(pedido.fecha_entrega_hasta) ||
    parseDate(pedido.fecha_entrega_fin) ||
    parseDate(pedido.fecha_entrega_extendida) ||
    parseDate(pedido.fecha_entrega_estimada_hasta) ||
    start;
  const safeEnd = end.getTime() < start.getTime() ? start : end;
  const title = pedido.codigo || (pedido.numero ? `#${pedido.numero}` : "Pedido");
  const cliente = pedido.expand?.cliente?.nombre || "Sin cliente";
  return { id: pedido.id, title, cliente, start, end: safeEnd, pedido };
}

function monthWeeks(month: Date): Date[][] {
  const first = new Date(month.getFullYear(), month.getMonth(), 1);
  const start = addDays(first, -weekdayIndex(first));
  const weeks: Date[][] = [];
  for (let w = 0; w < 6; w += 1) {
    const week = Array.from({ length: 7 }, (_, d) => addDays(start, w * 7 + d));
    weeks.push(week);
  }
  return weeks;
}

function parseDate(value: string | null | undefined): Date | null {
  const normalized = dateInputValue(value);
  if (!normalized) return null;
  const [year, month, day] = normalized.split("-").map(Number);
  return new Date(year, month - 1, day);
}

function eventOverlapsRange(event: DeliveryEvent, start: Date, end: Date): boolean {
  return event.start.getTime() <= end.getTime() && event.end.getTime() >= start.getTime();
}

function weekdayIndex(date: Date): number {
  return (date.getDay() + 6) % 7;
}

function addDays(date: Date, days: number): Date {
  return new Date(date.getFullYear(), date.getMonth(), date.getDate() + days);
}

function startOfDay(date: Date): Date {
  return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}

function dayKey(date: Date): string {
  const y = date.getFullYear();
  const m = String(date.getMonth() + 1).padStart(2, "0");
  const d = String(date.getDate()).padStart(2, "0");
  return `${y}-${m}-${d}`;
}

function daysBetween(start: Date, end: Date): number {
  return Math.round((startOfDay(end).getTime() - startOfDay(start).getTime()) / 86400000);
}

function minDate(a: Date, b: Date): Date {
  return a.getTime() <= b.getTime() ? a : b;
}

function maxDate(a: Date, b: Date): Date {
  return a.getTime() >= b.getTime() ? a : b;
}
