// routes/_authenticated/carreras.tsx (refactor a TanStack Query v5)
import { createFileRoute, useRouter } from "@tanstack/react-router"
import { useEffect, useMemo, useState } from "react"
import { useSuspenseQuery, useQueryClient, queryOptions, useQuery } from "@tanstack/react-query"
import { supabase } from "@/auth/supabase"
import * as Icons from "lucide-react"

import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { Label } from "@/components/ui/label"
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "@/components/ui/select"
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@/components/ui/accordion"
import { Switch } from "@/components/ui/switch"

/* -------------------- Tipos -------------------- */
type FacultadLite = { id: string; nombre: string; color?: string | null; icon?: string | null }
export type CarreraRow = {
  id: string
  nombre: string
  semestres: number
  activo: boolean
  facultad_id: string | null
  facultades?: FacultadLite | null
}

/* -------------------- Query Keys & Fetchers -------------------- */
const carrerasKeys = {
  root: ["carreras"] as const,
  list: () => [...carrerasKeys.root, "list"] as const,
}
const facultadesKeys = {
  root: ["facultades"] as const,
  all: () => [...facultadesKeys.root, "all"] as const,
}
const criteriosKeys = {
  root: ["criterios_carrera"] as const,
  byCarrera: (id: string) => [...criteriosKeys.root, { carreraId: id }] as const,
}

async function fetchCarreras(): Promise<CarreraRow[]> {
  const { data, error } = await supabase
    .from("carreras")
    .select(
      `id, nombre, semestres, activo, facultad_id, facultades:facultades ( id, nombre, color, icon )`
    )
    .order("nombre", { ascending: true })
  if (error) throw error
  return (data ?? []) as unknown as CarreraRow[]
}

async function fetchFacultades(): Promise<FacultadLite[]> {
  const { data, error } = await supabase
    .from("facultades")
    .select("id, nombre, color, icon")
    .order("nombre", { ascending: true })
  if (error) throw error
  return (data ?? []) as FacultadLite[]
}

export type CriterioRow = {
  id: number
  nombre: string
  descripcion: string | null
  tipo: string | null
  obligatorio: boolean | null
  referencia_documento: string | null
  fecha_creacion: string | null
}

async function fetchCriterios(carreraId: string): Promise<CriterioRow[]> {
  const { data, error } = await supabase
    .from("criterios_carrera")
    .select("id, nombre, descripcion, tipo, obligatorio, referencia_documento, fecha_creacion")
    .eq("carrera_id", carreraId)
    .order("fecha_creacion", { ascending: true })
  if (error) throw error
  return (data ?? []) as CriterioRow[]
}

const carrerasOptions = () =>
  queryOptions({ queryKey: carrerasKeys.list(), queryFn: fetchCarreras, staleTime: 60_000 })

const facultadesOptions = () =>
  queryOptions({ queryKey: facultadesKeys.all(), queryFn: fetchFacultades, staleTime: 5 * 60_000 })

const criteriosOptions = (carreraId: string) =>
  queryOptions({ queryKey: criteriosKeys.byCarrera(carreraId), queryFn: () => fetchCriterios(carreraId) })

/* -------------------- Ruta -------------------- */
export const Route = createFileRoute("/_authenticated/carreras")({
  component: RouteComponent,
  // Prefetch con TanStack Query (sin llamadas sueltas a Supabase fuera de QueryClient)
  loader: async ({ context: { queryClient } }) => {
    await Promise.all([
      queryClient.ensureQueryData(carrerasOptions()),
      queryClient.ensureQueryData(facultadesOptions()),
    ])
    return null
  },
})

/* -------------------- Helpers UI -------------------- */
const tint = (hex?: string | null, a = 0.18) => {
  if (!hex) return `rgba(37,99,235,${a})`
  const h = hex.replace("#", "")
  const v = h.length === 3 ? h.split("").map((c) => c + c).join("") : h
  const n = parseInt(v, 16)
  const r = (n >> 16) & 255,
    g = (n >> 8) & 255,
    b = n & 255
  return `rgba(${r},${g},${b},${a})`
}
const StatusPill = ({ active }: { active: boolean }) => (
  <span
    className={`text-[10px] px-2 py-0.5 rounded-full border ${
      active
        ? "bg-emerald-50 text-emerald-700 border-emerald-200"
        : "bg-neutral-100 text-neutral-700 border-neutral-200"
    }`}
  >
    {active ? "Activa" : "Inactiva"}
  </span>
)

/* -------------------- Página -------------------- */
function RouteComponent() {
  const router = useRouter()
  const qc = useQueryClient()

  const { data: carreras } = useSuspenseQuery(carrerasOptions())
  const { data: facultades } = useSuspenseQuery(facultadesOptions())

  const [q, setQ] = useState("")
  const [fac, setFac] = useState<string>("todas")
  const [state, setState] = useState<"todas" | "activas" | "inactivas">("todas")

  const [detail, setDetail] = useState<CarreraRow | null>(null)
  const [editCarrera, setEditCarrera] = useState<CarreraRow | null>(null)
  const [createOpen, setCreateOpen] = useState(false)

  const filtered = useMemo(() => {
    const term = q.trim().toLowerCase()
    return carreras.filter((c) => {
      if (fac !== "todas" && c.facultad_id !== fac) return false
      if (state === "activas" && !c.activo) return false
      if (state === "inactivas" && c.activo) return false
      if (!term) return true
      return [c.nombre, c.facultades?.nombre].filter(Boolean).some((v) => String(v).toLowerCase().includes(term))
    })
  }, [q, fac, state, carreras])

  return (
    <div className="p-6 space-y-4">
      <Card>
        <CardHeader className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
          <CardTitle>Carreras</CardTitle>
          <div className="flex w-full flex-col gap-2 md:w-auto md:flex-row md:items-center">
            <div className="relative w-full md:w-80">
              <Icons.Search className="absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-neutral-400" />
              <Input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Buscar por nombre o facultad…" className="pl-8" />
            </div>

            <Select value={fac} onValueChange={(v) => setFac(v)}>
              <SelectTrigger className="md:w-[220px]"><SelectValue placeholder="Facultad" /></SelectTrigger>
              <SelectContent>
                <SelectItem value="todas">Todas las facultades</SelectItem>
                {facultades.map((f) => (
                  <SelectItem key={f.id} value={f.id}>
                    {f.nombre}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>

            <Select value={state} onValueChange={(v: any) => setState(v)}>
              <SelectTrigger className="md:w-[160px]"><SelectValue placeholder="Estado" /></SelectTrigger>
              <SelectContent>
                <SelectItem value="todas">Todas</SelectItem>
                <SelectItem value="activas">Activas</SelectItem>
                <SelectItem value="inactivas">Inactivas</SelectItem>
              </SelectContent>
            </Select>

            <Button
              variant="outline"
              size="icon"
              onClick={async () => {
                await Promise.all([
                  qc.invalidateQueries({ queryKey: carrerasKeys.root }),
                  qc.invalidateQueries({ queryKey: facultadesKeys.root }),
                ])
                router.invalidate()
              }}
              title="Recargar"
            >
              <Icons.RefreshCcw className="h-4 w-4" />
            </Button>

            <Button onClick={() => setCreateOpen(true)}>
              <Icons.Plus className="h-4 w-4 mr-2" /> Nueva carrera
            </Button>
          </div>
        </CardHeader>

        <CardContent>
          <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
            {filtered.map((c) => {
              const fac = c.facultades
              const border = tint(fac?.color, 0.28)
              const chip = tint(fac?.color, 0.1)
              const IconComp = (fac?.icon && (Icons as any)[fac.icon]) || Icons.Building2
              return (
                <article
                  key={c.id}
                  className="group relative overflow-hidden rounded-3xl bg-white shadow-sm ring-1 transition-all hover:shadow-md hover:-translate-y-0.5"
                  style={{ borderColor: border, background: `linear-gradient(180deg, ${chip}, transparent)` }}
                >
                  <div className="p-5 h-44 flex flex-col justify-between">
                    <div className="flex items-center gap-3">
                      <span className="inline-flex items-center justify-center rounded-2xl border px-2.5 py-2 bg-white/70" style={{ borderColor: border }}>
                        <IconComp className="w-6 h-6" />
                      </span>
                      <div className="min-w-0">
                        <div className="font-semibold truncate">{c.nombre}</div>
                        <div className="text-xs text-neutral-600 truncate">{fac?.nombre ?? "—"} · {c.semestres} semestres</div>
                      </div>
                    </div>

                    <div className="mt-2 flex items-center justify-between">
                      <StatusPill active={c.activo} />
                      <div className="flex items-center gap-1.5">
                        <Button variant="ghost" size="sm" onClick={() => setDetail(c)}>
                          <Icons.Eye className="w-4 h-4 mr-1" /> Ver
                        </Button>
                        <Button variant="ghost" size="sm" onClick={() => setEditCarrera(c)}>
                          <Icons.Pencil className="w-4 h-4 mr-1" /> Editar
                        </Button>
                      </div>
                    </div>
                  </div>
                </article>
              )
            })}
          </div>

          {!filtered.length && <div className="text-center text-sm text-neutral-500 py-10">No hay resultados</div>}
        </CardContent>
      </Card>

      {/* Crear / Editar */}
      <CarreraFormDialog
        open={createOpen}
        onOpenChange={setCreateOpen}
        facultades={facultades}
        mode="create"
        onSaved={async () => {
          await qc.invalidateQueries({ queryKey: carrerasKeys.root })
          router.invalidate()
        }}
      />
      <CarreraFormDialog
        open={!!editCarrera}
        onOpenChange={(o) => !o && setEditCarrera(null)}
        facultades={facultades}
        mode="edit"
        carrera={editCarrera ?? undefined}
        onSaved={async () => {
          setEditCarrera(null)
          await qc.invalidateQueries({ queryKey: carrerasKeys.root })
          router.invalidate()
        }}
      />

      {/* Detalle + añadir criterio */}
      <CarreraDetailDialog
        carrera={detail}
        onOpenChange={setDetail}
        onChanged={async () => {
          await qc.invalidateQueries({ queryKey: carrerasKeys.root })
          if (detail) await qc.invalidateQueries({ queryKey: criteriosKeys.byCarrera(detail.id) })
        }}
      />
    </div>
  )
}

/* -------------------- Form crear/editar -------------------- */
function CarreraFormDialog({
  open,
  onOpenChange,
  mode,
  carrera,
  facultades,
  onSaved,
}: {
  open: boolean
  onOpenChange: (o: boolean) => void
  mode: "create" | "edit"
  carrera?: CarreraRow
  facultades: FacultadLite[]
  onSaved?: () => void
}) {
  const [saving, setSaving] = useState(false)
  const [nombre, setNombre] = useState(carrera?.nombre ?? "")
  const [semestres, setSemestres] = useState<number>(carrera?.semestres ?? 9)
  const [activo, setActivo] = useState<boolean>(carrera?.activo ?? true)
  const [facultadId, setFacultadId] = useState<string | "none">(carrera?.facultad_id ?? "none")

  useEffect(() => {
    if (mode === "edit" && carrera) {
      setNombre(carrera.nombre)
      setSemestres(carrera.semestres)
      setActivo(carrera.activo)
      setFacultadId(carrera.facultad_id ?? "none")
    } else if (mode === "create") {
      setNombre("")
      setSemestres(9)
      setActivo(true)
      setFacultadId("none")
    }
  }, [mode, carrera, open])

  async function save() {
    if (!nombre.trim()) {
      alert("Escribe un nombre")
      return
    }
    setSaving(true)
    const payload = {
      nombre: nombre.trim(),
      semestres: Number(semestres) || 9,
      activo,
      facultad_id: facultadId === "none" ? null : facultadId,
    }

    const action =
      mode === "create"
        ? supabase.from("carreras").insert([payload]).select("id").single()
        : supabase.from("carreras").update(payload).eq("id", carrera!.id).select("id").single()

    const { error } = await action
    setSaving(false)
    if (error) {
      alert(error.message)
      return
    }
    onOpenChange(false)
    onSaved?.()
  }

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-w-lg">
        <DialogHeader>
          <DialogTitle>{mode === "create" ? "Nueva carrera" : "Editar carrera"}</DialogTitle>
          <DialogDescription>
            {mode === "create" ? "Crea una nueva carrera en la base de datos." : "Actualiza los datos de la carrera."}
          </DialogDescription>
        </DialogHeader>

        <div className="grid gap-3">
          <div className="space-y-1">
            <Label>Nombre</Label>
            <Input value={nombre} onChange={(e) => setNombre(e.target.value)} placeholder="Ing. en Software" />
          </div>

          <div className="grid grid-cols-2 gap-3">
            <div className="space-y-1">
              <Label>Semestres</Label>
              <Input type="number" min={1} max={20} value={semestres} onChange={(e) => setSemestres(parseInt(e.target.value || "9", 10))} />
            </div>
            <div className="space-y-1">
              <Label>Estado</Label>
              <div className="flex h-10 items-center gap-2 rounded-md border px-3">
                <Switch checked={activo} onCheckedChange={setActivo} />
                <span className="text-sm">{activo ? "Activa" : "Inactiva"}</span>
              </div>
            </div>
          </div>

          <div className="space-y-1">
            <Label>Facultad</Label>
            <Select value={facultadId} onValueChange={(v) => setFacultadId(v as any)}>
              <SelectTrigger>
                <SelectValue placeholder="Selecciona una facultad (opcional)" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="none">Sin facultad</SelectItem>
                {facultades.map((f) => (
                  <SelectItem key={f.id} value={f.id}>
                    {f.nombre}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
        </div>

        <DialogFooter>
          <Button variant="outline" onClick={() => onOpenChange(false)}>
            Cancelar
          </Button>
          <Button onClick={save} disabled={saving}>
            {saving ? "Guardando…" : mode === "create" ? "Crear" : "Guardar"}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}

/* -------------------- Detalle (criterios) -------------------- */
function CarreraDetailDialog({
  carrera,
  onOpenChange,
  onChanged,
}: {
  carrera: CarreraRow | null
  onOpenChange: (c: CarreraRow | null) => void
  onChanged?: () => void
}) {
  const carreraId = carrera?.id ?? ""
  const { data: criterios = [], isFetching } = useQuery({
    ...criteriosOptions(carreraId || "noop"),
    enabled: !!carreraId,
  })
  const [q, setQ] = useState("")
  const [newCritOpen, setNewCritOpen] = useState(false)

  const filtered = useMemo(() => {
    const t = q.trim().toLowerCase()
    if (!t) return criterios
    return criterios.filter((c) =>
      [c.nombre, c.descripcion, c.tipo, c.referencia_documento].filter(Boolean).some((v) => String(v).toLowerCase().includes(t))
    )
  }, [q, criterios])

  return (
    <Dialog open={!!carrera} onOpenChange={(o) => !o && onOpenChange(null)}>
      <DialogContent className="max-w-3xl">
        <DialogHeader>
          <DialogTitle>{carrera?.nombre}</DialogTitle>
          <DialogDescription>
            {carrera?.facultades?.nombre ?? "—"} · {carrera?.semestres} semestres {typeof carrera?.activo === "boolean" && (
              <Badge variant="outline" className="ml-2">
                {carrera?.activo ? "Activa" : "Inactiva"}
              </Badge>
            )}
          </DialogDescription>
        </DialogHeader>

        <div className="space-y-3">
          <div className="flex items-center justify-between gap-2">
            <div className="relative flex-1">
              <Icons.Search className="absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-neutral-400" />
              <Input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Buscar criterio por nombre, tipo o referencia…" className="pl-8" />
            </div>
            <Button onClick={() => setNewCritOpen(true)}>
              <Icons.Plus className="h-4 w-4 mr-2" /> Añadir criterio
            </Button>
          </div>

          {isFetching ? (
            <div className="text-sm text-neutral-500">Cargando criterios…</div>
          ) : (
            <>
              <div className="text-xs text-neutral-600">{filtered.length} criterio(s){q ? " (filtrado)" : ""}</div>

              {filtered.length === 0 ? (
                <div className="text-sm text-neutral-500 py-6 text-center">No hay criterios</div>
              ) : (
                <Accordion type="multiple" className="mt-1">
                  {filtered.map((c) => (
                    <AccordionItem key={c.id} value={`c-${c.id}`} className="border rounded-xl mb-2 overflow-hidden">
                      <AccordionTrigger className="px-4 py-2 hover:no-underline text-left">
                        <div className="flex items-center justify-between w-full">
                          <span className="font-medium">{c.nombre}</span>
                          <div className="flex items-center gap-2 text-[11px]">
                            {c.tipo && <Badge variant="outline">{c.tipo}</Badge>}
                            <Badge variant="outline">{c.obligatorio ? "Obligatorio" : "Opcional"}</Badge>
                          </div>
                        </div>
                      </AccordionTrigger>
                      <AccordionContent className="px-5 pb-3">
                        {c.descripcion && <p className="text-sm text-neutral-800 leading-relaxed mb-2">{c.descripcion}</p>}
                        <div className="text-xs text-neutral-600 flex flex-wrap gap-3">
                          {c.referencia_documento && (
                            <span className="inline-flex items-center gap-1">
                              <Icons.Link className="h-3 w-3" />
                              <a className="underline" href={c.referencia_documento} target="_blank" rel="noreferrer">
                                Referencia
                              </a>
                            </span>
                          )}
                          {c.fecha_creacion && (
                            <span className="inline-flex items-center gap-1">
                              <Icons.CalendarClock className="h-3 w-3" />
                              {new Date(c.fecha_creacion).toLocaleString()}
                            </span>
                          )}
                        </div>
                      </AccordionContent>
                    </AccordionItem>
                  ))}
                </Accordion>
              )}
            </>
          )}
        </div>

        <DialogFooter>
          <Button onClick={() => onOpenChange(null)}>Cerrar</Button>
        </DialogFooter>

        {/* Crear criterio */}
        <CriterioFormDialog
          open={newCritOpen}
          onOpenChange={setNewCritOpen}
          carreraId={carrera?.id ?? ""}
          onSaved={onChanged}
        />
      </DialogContent>
    </Dialog>
  )
}

/* -------------------- Form crear criterio -------------------- */
function CriterioFormDialog({
  open,
  onOpenChange,
  carreraId,
  onSaved,
}: {
  open: boolean
  onOpenChange: (o: boolean) => void
  carreraId: string
  onSaved?: () => void
}) {
  const qc = useQueryClient()
  const [saving, setSaving] = useState(false)
  const [nombre, setNombre] = useState("")
  const [tipo, setTipo] = useState<string>("")
  const [descripcion, setDescripcion] = useState("")
  const [obligatorio, setObligatorio] = useState(true)
  const [referencia, setReferencia] = useState("")

  useEffect(() => {
    if (!open) {
      setNombre("")
      setTipo("")
      setDescripcion("")
      setObligatorio(true)
      setReferencia("")
    }
  }, [open])

  async function save() {
    if (!carreraId) return
    if (!nombre.trim()) {
      alert("Escribe un nombre")
      return
    }
    setSaving(true)
    const { error } = await supabase.from("criterios_carrera").insert([
      {
        nombre: nombre.trim(),
        tipo: tipo || null,
        descripcion: descripcion || null,
        obligatorio,
        referencia_documento: referencia || null,
        carrera_id: carreraId,
      },
    ])
    setSaving(false)
    if (error) {
      alert(error.message)
      return
    }
    onOpenChange(false)
    await qc.invalidateQueries({ queryKey: criteriosKeys.byCarrera(carreraId) })
    onSaved?.()
  }

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-w-lg">
        <DialogHeader>
          <DialogTitle>Nuevo criterio</DialogTitle>
          <DialogDescription>Agrega un criterio para esta carrera.</DialogDescription>
        </DialogHeader>

        <div className="grid gap-3">
          <div className="space-y-1">
            <Label>Nombre</Label>
            <Input value={nombre} onChange={(e) => setNombre(e.target.value)} placeholder="Infraestructura de laboratorios" />
          </div>
          <div className="space-y-1">
            <Label>Tipo</Label>
            <Input value={tipo} onChange={(e) => setTipo(e.target.value)} placeholder="Académico / Operativo / Otro" />
          </div>
          <div className="space-y-1">
            <Label>Descripción</Label>
            <Input value={descripcion} onChange={(e) => setDescripcion(e.target.value)} placeholder="Detalle o alcance del criterio" />
          </div>
          <div className="grid grid-cols-2 gap-3 items-center">
            <div className="space-y-1">
              <Label>¿Obligatorio?</Label>
              <div className="flex h-10 items-center gap-2 rounded-md border px-3">
                <Switch checked={obligatorio} onCheckedChange={setObligatorio} />
                <span className="text-sm">{obligatorio ? "Sí" : "No"}</span>
              </div>
            </div>
            <div className="space-y-1">
              <Label>Referencia (URL)</Label>
              <Input value={referencia} onChange={(e) => setReferencia(e.target.value)} placeholder="https://…" />
            </div>
          </div>
        </div>

        <DialogFooter>
          <Button variant="outline" onClick={() => onOpenChange(false)}>
            Cancelar
          </Button>
          <Button onClick={save} disabled={saving}>
            {saving ? "Guardando…" : "Crear"}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}
