// routes/_authenticated/asignaturas/$planId.tsx
import { createFileRoute, Link, useRouter } from "@tanstack/react-router"
import { supabase } from "@/auth/supabase"
import * as Icons from "lucide-react"
import { useEffect, useMemo, useRef, useState } from "react"
import {
  Dialog, DialogContent, DialogHeader, DialogTitle,
} from "@/components/ui/dialog"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
import {
  DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import {
  Select, SelectTrigger, SelectContent, SelectItem, SelectValue,
} from "@/components/ui/select"
import { Badge } from "@/components/ui/badge"

/* ================== Tipos ================== */
type Asignatura = {
  id: string
  nombre: string
  clave: string | null
  tipo: string | null
  semestre: number | null
  creditos: number | null
  horas_teoricas: number | null
  horas_practicas: number | null
  objetivos: string | null
  contenidos: Record<string, Record<string, string>> | null
  bibliografia: string[] | null
  criterios_evaluacion: string | null
}

type ModalData = {
  planId: string
  planNombre: string
  asignaturas: Asignatura[]
}

/* ================== Ruta (modal) ================== */
export const Route = createFileRoute("/_authenticated/asignaturas/$planId")({
  component: Page,
  loader: async ({ params }): Promise<ModalData> => {
    const planId = params.planId

    const { data: plan, error: planErr } = await supabase
      .from("plan_estudios")
      .select("id, nombre")
      .eq("id", planId)
      .single()
    if (planErr || !plan) throw planErr ?? new Error("Plan no encontrado")

    const { data: asignaturas, error: aErr } = await supabase
      .from("asignaturas")
      .select(`
        id, nombre, clave, tipo, semestre, creditos, horas_teoricas, horas_practicas,
        objetivos, contenidos, bibliografia, criterios_evaluacion
      `)
      .eq("plan_id", planId)
      .order("semestre", { ascending: true })
      .order("nombre", { ascending: true })
    if (aErr) throw aErr

    return { planId, planNombre: plan.nombre, asignaturas: (asignaturas ?? []) as Asignatura[] }
  },
})

/* ================== Página ================== */
function Page() {
  const { planId, planNombre, asignaturas } = Route.useLoaderData() as ModalData
  const router = useRouter()

  // ---- estado UI
  const [query, setQuery] = useState("")
  const [sem, setSem] = useState<string>("todos")
  const [tipo, setTipo] = useState<string>("todos")
  const [orden, setOrden] = useState<"nombre" | "semestre" | "creditos">("semestre")
  const [vista, setVista] = useState<"cards" | "tabla">("cards")

  // ---- atajos
  const searchRef = useRef<HTMLInputElement | null>(null)
  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      const meta = e.ctrlKey || e.metaKey
      if (meta && e.key.toLowerCase() === "k") {
        e.preventDefault()
        searchRef.current?.focus()
      }
      if (e.key === "Escape") {
        router.navigate({ to: "/plan/$planId", params: { planId }, replace: true })
      }
    }
    window.addEventListener("keydown", onKey)
    return () => window.removeEventListener("keydown", onKey)
  }, [router, planId])

  // ---- semestres y tipos disponibles
  const semestres = useMemo(() => {
    const s = new Set<string>()
    asignaturas.forEach(a => s.add(String(a.semestre ?? "—")))
    return Array.from(s).sort((a, b) => (a === "—" ? 1 : 0) - (b === "—" ? 1 : 0) || Number(a) - Number(b))
  }, [asignaturas])
  const tipos = useMemo(() => {
    const s = new Set<string>()
    asignaturas.forEach(a => s.add(a.tipo ?? "—"))
    return Array.from(s).sort()
  }, [asignaturas])

  // ---- KPIs
  const kpis = useMemo(() => {
    const total = asignaturas.length
    const creditos = asignaturas.reduce((acc, a) => acc + (a.creditos ?? 0), 0)
    const ht = asignaturas.reduce((acc, a) => acc + (a.horas_teoricas ?? 0), 0)
    const hp = asignaturas.reduce((acc, a) => acc + (a.horas_practicas ?? 0), 0)
    const porTipo: Record<string, number> = {}
    asignaturas.forEach(a => {
      const key = (a.tipo ?? "—").toLowerCase()
      porTipo[key] = (porTipo[key] ?? 0) + 1
    })
    return { total, creditos, ht, hp, porTipo }
  }, [asignaturas])

  // ---- filtro + orden
  const filtradas = useMemo(() => {
    const t = query.trim().toLowerCase()
    const list = asignaturas.filter(a => {
      const matchTexto =
        !t ||
        [a.nombre, a.clave, a.tipo, a.objetivos]
          .filter(Boolean)
          .some(v => String(v).toLowerCase().includes(t))
      const semOK = sem === "todos" || String(a.semestre ?? "—") === sem
      const tipoOK = tipo === "todos" || (a.tipo ?? "—") === tipo
      return matchTexto && semOK && tipoOK
    })

    const sortList = [...list].sort((A, B) => {
      if (orden === "nombre") return A.nombre.localeCompare(B.nombre)
      if (orden === "creditos") return (B.creditos ?? 0) - (A.creditos ?? 0)
      // semestre
      const a = A.semestre ?? 999
      const b = B.semestre ?? 999
      if (a === b) return A.nombre.localeCompare(B.nombre)
      return a - b
    })

    return sortList
  }, [asignaturas, query, sem, tipo, orden])

  // ---- agrupación por semestre (para la vista de cards)
  const grupos = useMemo(() => {
    const m = new Map<number | string, Asignatura[]>()
    for (const a of filtradas) {
      const k = a.semestre ?? "—"
      if (!m.has(k)) m.set(k, [])
      m.get(k)!.push(a)
    }
    return Array.from(m.entries()).sort(([a], [b]) => {
      if (a === "—") return 1
      if (b === "—") return -1
      return Number(a) - Number(b)
    })
  }, [filtradas])

  // ---- helpers
  const limpiar = () => { setQuery(""); setSem("todos"); setTipo("todos"); setOrden("semestre") }

  return (
    <Dialog
      open
      onOpenChange={() => router.navigate({ to: "/plan/$planId", params: { planId }, replace: true })}
    >
      <DialogContent className="p-0 min-w-[94vw] h-[min(94vh,920px)] sm:rounded-2xl overflow-hidden flex flex-col">
        {/* HERO ===================================================== */}
        <div className="relative">
          <div className="absolute inset-0 bg-gradient-to-br from-primary/20 via-primary/10 to-transparent" />
          <div className="relative px-5 pt-5 pb-3 flex items-center justify-between gap-3">
            <div className="min-w-0">
              <div className="flex items-center gap-2 text-xs text-neutral-500">
                <Icons.ScrollText className="h-4 w-4" />
                Plan
              </div>
              <DialogHeader className="p-0">
                <DialogTitle className="truncate text-xl sm:text-2xl">{planNombre}</DialogTitle>
              </DialogHeader>
              <div className="mt-2 flex flex-wrap items-center gap-2 text-xs">
                <KpiChip icon={Icons.BookOpen} label="Asignaturas" value={kpis.total} />
                <KpiChip icon={Icons.Coins} label="Créditos" value={kpis.creditos} />
                <KpiChip icon={Icons.Clock} label="Horas T/P" value={`${kpis.ht}/${kpis.hp}`} />
                {Object.entries(kpis.porTipo).slice(0, 3).map(([t, n]) => (
                  <Badge key={t} variant="secondary" className="text-[10px]">
                    {t} · {n}
                  </Badge>
                ))}
              </div>
            </div>

            <div className="flex items-center gap-2">
              <Button variant="outline" size="sm" asChild>
                <Link to="/plan/$planId" params={{ planId }}>Ir al plan</Link>
              </Button>
            </div>
          </div>

          {/* TOOLBAR sticky ========================================= */}
          <div className="sticky top-0 z-10 border-y bg-white/90 backdrop-blur">
            <div className="px-5 py-3 grid gap-2 items-center
                            sm:grid-cols-[1fr,140px,160px,160px,auto]">
              <div className="relative">
                <Icons.Search className="absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-neutral-400" />
                <Input
                  ref={searchRef}
                  value={query}
                  onChange={(e) => setQuery(e.target.value)}
                  placeholder="Buscar (⌘/Ctrl K)…"
                  className="pl-8"
                />
              </div>

              <Select value={sem} onValueChange={setSem}>
                <SelectTrigger className="w-full"><SelectValue placeholder="Semestre" /></SelectTrigger>
                <SelectContent>
                  <SelectItem value="todos">Todos</SelectItem>
                  {semestres.map(s => <SelectItem key={s} value={s}>Semestre {s}</SelectItem>)}
                </SelectContent>
              </Select>

              <Select value={tipo} onValueChange={setTipo}>
                <SelectTrigger className="w-full"><SelectValue placeholder="Tipo" /></SelectTrigger>
                <SelectContent className="max-h-64">
                  <SelectItem value="todos">Todos</SelectItem>
                  {tipos.map(t => <SelectItem key={t} value={t}>{t}</SelectItem>)}
                </SelectContent>
              </Select>

              <Select value={orden} onValueChange={(v) => setOrden(v as any)}>
                <SelectTrigger className="w-full"><SelectValue placeholder="Ordenar por" /></SelectTrigger>
                <SelectContent>
                  <SelectItem value="semestre">Semestre</SelectItem>
                  <SelectItem value="nombre">Nombre</SelectItem>
                  <SelectItem value="creditos">Créditos</SelectItem>
                </SelectContent>
              </Select>

              <div className="flex items-center justify-end gap-2">
                <ViewToggle value={vista} onChange={setVista} />
                {(query || sem !== "todos" || tipo !== "todos" || orden !== "semestre") && (
                  <Button variant="ghost" size="sm" onClick={limpiar}>
                    <Icons.Eraser className="h-4 w-4 mr-1" /> Limpiar
                  </Button>
                )}
              </div>
            </div>
          </div>
        </div>

        {/* CONTENIDO scrolleable ==================================== */}
        <div className="flex-1 overflow-auto px-5 py-5">
          {filtradas.length === 0 ? (
            <EmptyState />
          ) : vista === "tabla" ? (
            <Tabla asignaturas={filtradas} />
          ) : (
            <div className="space-y-8">
              {grupos.map(([sem, items]) => (
                <section key={String(sem)} className="space-y-3">
                  <h3 className="text-xs font-semibold text-neutral-600">Semestre {sem}</h3>
                  <ul className="grid gap-3 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4">
                    {items.map(a => <AsignaturaCard key={a.id} a={a} />)}
                  </ul>
                </section>
              ))}
            </div>
          )}
        </div>
      </DialogContent>
    </Dialog>
  )
}

/* ================== UI bits ================== */
function KpiChip({ icon: Icon, label, value }:{ icon: any; label: string; value: number | string }) {
  return (
    <span className="inline-flex items-center gap-1 rounded-full border bg-white/60 px-2 py-0.5 text-[11px]">
      <Icon className="h-3.5 w-3.5" /> {label}: <span className="font-medium">{value}</span>
    </span>
  )
}

function ViewToggle({ value, onChange }:{ value:"cards"|"tabla"; onChange:(v:"cards"|"tabla")=>void }) {
  return (
    <div className="inline-flex rounded-lg border bg-white overflow-hidden">
      <button
        className={`px-2.5 py-1.5 text-xs flex items-center gap-1 ${value==="cards" ? "bg-neutral-100" : ""}`}
        onClick={() => onChange("cards")}
        title="Tarjetas"
      >
        <Icons.LayoutGrid className="h-4 w-4" /> Cards
      </button>
      <button
        className={`px-2.5 py-1.5 text-xs flex items-center gap-1 border-l ${value==="tabla" ? "bg-neutral-100" : ""}`}
        onClick={() => onChange("tabla")}
        title="Tabla compacta"
      >
        <Icons.Table2 className="h-4 w-4" /> Tabla
      </button>
    </div>
  )
}

function EmptyState() {
  return (
    <div className="grid place-items-center h-[48vh]">
      <div className="text-center max-w-sm">
        <div className="mx-auto w-12 h-12 rounded-2xl grid place-items-center bg-neutral-100">
          <Icons.Inbox className="h-6 w-6 text-neutral-500" />
        </div>
        <h4 className="mt-3 font-semibold">Sin resultados</h4>
        <p className="text-sm text-neutral-600">Ajusta los filtros o la búsqueda.</p>
      </div>
    </div>
  )
}

/* ================== Card ================== */

function tipoMeta(tipo?: string | null) {
  const t = (tipo ?? "").toLowerCase()
  if (t.includes("oblig")) return { label: "Obligatoria", color: "emerald" }
  if (t.includes("opt"))    return { label: "Optativa", color: "amber" }
  if (t.includes("taller")) return { label: "Taller", color: "indigo" }
  if (t.includes("lab"))    return { label: "Laboratorio", color: "sky" }
  return { label: tipo ?? "Genérica", color: "neutral" }
}

function AsignaturaCard({ a }: { a: Asignatura }) {
  const horasT = a.horas_teoricas ?? 0
  const horasP = a.horas_practicas ?? 0
  const meta = tipoMeta(a.tipo)

  return (
    <li className="group relative overflow-hidden rounded-2xl border bg-white/75 shadow-sm hover:shadow-md transition-all">
      {/* franja lateral por tipo */}
      <span
        aria-hidden
        className={`absolute left-0 top-0 h-full w-1 bg-${meta.color}-500/80`}
      />
      <div className="p-3 pl-4">
        <div className="flex items-start gap-3">
          <div className={`mt-0.5 h-8 w-8 rounded-xl grid place-items-center border bg-white/80`}>
            <Icons.BookOpen className="h-4 w-4" />
          </div>

          <div className="min-w-0 flex-1">
            <h4 className="font-semibold leading-tight truncate" title={a.nombre}>{a.nombre}</h4>
            <div className="mt-1 flex flex-wrap items-center gap-1.5 text-[11px]">
              {a.clave && <Chip><Icons.KeyRound className="h-3 w-3" /> {a.clave}</Chip>}
              <Chip className={`bg-${meta.color}-50 text-${meta.color}-800 border-${meta.color}-200`}>
                <Icons.BadgeCheck className="h-3 w-3" /> {meta.label}
              </Chip>
              {a.creditos != null && <Chip><Icons.Coins className="h-3 w-3" /> {a.creditos} créditos</Chip>}
              {(horasT + horasP) > 0 && <Chip><Icons.Clock className="h-3 w-3" /> H T/P: {horasT}/{horasP}</Chip>}
              <Chip><Icons.CalendarDays className="h-3 w-3" /> Semestre {a.semestre ?? "—"}</Chip>
            </div>
          </div>

          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button variant="ghost" size="icon" className="mt-[-2px]">
                <Icons.MoreVertical className="h-4 w-4" />
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="end" className="min-w-[190px]">
              <DropdownMenuItem className="gap-2" asChild>
                <Link to="/asignatura/$asignaturaId" params={{ asignaturaId: a.id }}>
                  <Icons.FileText className="h-4 w-4" /> Ver detalles
                </Link>
              </DropdownMenuItem>
              <DropdownMenuItem className="gap-2">
                <Icons.Pencil className="h-4 w-4" /> Editar
              </DropdownMenuItem>
              <DropdownMenuItem className="gap-2">
                <Icons.Sparkles className="h-4 w-4" /> Ajustar con IA
              </DropdownMenuItem>
            </DropdownMenuContent>
          </DropdownMenu>
        </div>

        {/* objetivo (clamp) */}
        {a.objetivos && (
          <p className="mt-2 text-xs text-neutral-700 line-clamp-2">{a.objetivos}</p>
        )}

        {/* CTA */}
        <div className="mt-2 flex justify-end">
          <Link
            to="/asignatura/$asignaturaId"
            params={{ asignaturaId: a.id }}
            className="inline-flex items-center gap-1 rounded-lg border px-3 py-1.5 text-xs hover:bg-neutral-50"
          >
            Ver ficha <Icons.ArrowRight className="h-3.5 w-3.5" />
          </Link>
        </div>
      </div>
    </li>
  )
}

function Chip({ children, className = "" }:{ children: React.ReactNode; className?: string }) {
  return (
    <span className={`inline-flex items-center gap-1 rounded-full border bg-white/70 px-2 py-0.5 text-[11px] ${className}`}>
      {children}
    </span>
  )
}

/* ================== Tabla compacta ================== */
function Tabla({ asignaturas }: { asignaturas: Asignatura[] }) {
  return (
    <div className="rounded-2xl border bg-white/70 overflow-auto">
      <table className="min-w-full text-sm">
        <thead className="sticky top-0 bg-white/90 backdrop-blur text-[12px]">
          <tr className="[&>th]:px-3 [&>th]:py-2 text-left text-neutral-500">
            <th>Nombre</th>
            <th className="whitespace-nowrap">Clave</th>
            <th>Tipo</th>
            <th>Sem.</th>
            <th>Créditos</th>
            <th className="whitespace-nowrap">H T/P</th>
            <th></th>
          </tr>
        </thead>
        <tbody className="[&>tr:nth-child(odd)]:bg-neutral-50/40">
          {asignaturas.map(a => (
            <tr key={a.id} className="align-top">
              <td className="px-3 py-2">
                <div className="font-medium truncate max-w-[36ch]" title={a.nombre}>{a.nombre}</div>
                {a.objetivos && <div className="text-xs text-neutral-600 line-clamp-1 max-w-[56ch]">{a.objetivos}</div>}
              </td>
              <td className="px-3 py-2 text-neutral-700">{a.clave ?? "—"}</td>
              <td className="px-3 py-2">{a.tipo ?? "—"}</td>
              <td className="px-3 py-2 tabular-nums">{a.semestre ?? "—"}</td>
              <td className="px-3 py-2 tabular-nums">{a.creditos ?? "—"}</td>
              <td className="px-3 py-2 tabular-nums">
                {(a.horas_teoricas ?? 0)}/{(a.horas_practicas ?? 0)}
              </td>
              <td className="px-3 py-2">
                <div className="flex justify-end">
                  <DropdownMenu>
                    <DropdownMenuTrigger asChild>
                      <Button variant="ghost" size="icon">
                        <Icons.MoreVertical className="h-4 w-4" />
                      </Button>
                    </DropdownMenuTrigger>
                    <DropdownMenuContent align="end" className="min-w-[180px]">
                      <DropdownMenuItem asChild className="gap-2">
                        <Link to="/asignatura/$asignaturaId" params={{ asignaturaId: a.id }}>
                          <Icons.FileText className="h-4 w-4" /> Ver detalles
                        </Link>
                      </DropdownMenuItem>
                      <DropdownMenuItem className="gap-2">
                        <Icons.Pencil className="h-4 w-4" /> Editar
                      </DropdownMenuItem>
                      <DropdownMenuItem className="gap-2">
                        <Icons.Sparkles className="h-4 w-4" /> Ajustar con IA
                      </DropdownMenuItem>
                    </DropdownMenuContent>
                  </DropdownMenu>
                </div>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  )
}
