import { createFileRoute, Link, useRouter } from '@tanstack/react-router'
import { useSuspenseQuery, queryOptions, useQueryClient } from '@tanstack/react-query'
import { supabase } from '@/auth/supabase'
import * as Icons from 'lucide-react'
import { useMemo, useState } from 'react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Select, SelectTrigger, SelectContent, SelectItem, SelectValue } from '@/components/ui/select'
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from '@/components/ui/dropdown-menu'
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { Label } from '@/components/ui/label'
import { toast } from 'sonner'
import { InfoChip } from '@/components/planes/InfoChip'

/* ================== Tipos ================== */
type FacMini = { id: string; nombre: string; color?: string | null; icon?: string | null }
type CarMini = { id: string; nombre: string; facultad: FacMini | null }
type PlanMini = { id: string; nombre: string; carrera: CarMini | null }

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
  fecha_creacion: string | null
  plan: PlanMini | null
  // NEW: plan_id base (lo traemos en el SELECT)
  plan_id?: string | null
}

type SearchState = {
  q: string
  planId: string
  carreraId: string
  facultadId: string
  f: 'sinBibliografia' | 'sinCriterios' | 'sinContenidos' | ''
}

/* ================== Query Keys & Options ================== */
const asignaturasKeys = {
  root: ['asignaturas'] as const,
  list: (search: SearchState) => [...asignaturasKeys.root, { search }] as const,
}
const planesKeys = {
  root: ['planes'] as const,
  all: () => [...planesKeys.root, 'all'] as const,
}

async function fetchPlanIdsByScope(search: Pick<SearchState, 'planId' | 'carreraId' | 'facultadId'>): Promise<string[] | null> {
  const { planId, carreraId, facultadId } = search
  if (planId) return [planId]
  if (carreraId) {
    const { data, error } = await supabase.from('plan_estudios').select('id').eq('carrera_id', carreraId)
    if (error) throw error
    return (data ?? []).map(p => p.id)
  }
  if (facultadId) {
    const { data: carreras, error: carErr } = await supabase.from('carreras').select('id').eq('facultad_id', facultadId)
    if (carErr) throw carErr
    const cIds = (carreras ?? []).map(c => c.id)
    if (!cIds.length) return []
    const { data: planesFac, error: plaErr } = await supabase
      .from('plan_estudios')
      .select('id')
      .in('carrera_id', cIds)
    if (plaErr) throw plaErr
    return (planesFac ?? []).map(p => p.id)
  }
  return null
}

async function fetchAsignaturas(search: SearchState): Promise<Asignatura[]> {
  const planIds = await fetchPlanIdsByScope(search)
  if (planIds && planIds.length === 0) return []
  console.log(AsignaturaCard);

  let query = supabase
    .from('asignaturas')
    .select(`
      id, nombre, clave, tipo, semestre, creditos, horas_teoricas, horas_practicas,
      objetivos, contenidos, bibliografia, criterios_evaluacion, fecha_creacion, plan_id,
      plan:plan_estudios (
        id, nombre,
        carrera:carreras (
          id, nombre,
          facultad:facultades ( id, nombre, color, icon )
        )
      )
    `)
    .order('semestre', { ascending: true })
    .order('nombre', { ascending: true })
  if (planIds) query = query.in('plan_id', planIds)
  const { data, error } = await query
  if (error) throw error
  return (data ?? []) as unknown as Asignatura[]
}

async function fetchPlanes(): Promise<PlanMini[]> {
  const { data, error } = await supabase
    .from('plan_estudios')
    .select(`
      id, nombre,
      carrera:carreras(
        id, nombre,
        facultad:facultades(id, nombre, color, icon)
      )
    `)
    .order('nombre', { ascending: true })
  if (error) throw error
  return (data ?? []) as unknown as PlanMini[]
}

const asignaturasOptions = (search: SearchState) => queryOptions({
  queryKey: asignaturasKeys.list(search),
  queryFn: () => fetchAsignaturas(search),
  staleTime: 60_000,
})

const planesOptions = () => queryOptions({
  queryKey: planesKeys.all(),
  queryFn: fetchPlanes,
  staleTime: 5 * 60_000,
})

/* ================== Ruta ================== */
export const Route = createFileRoute('/_authenticated/asignaturas')({
  component: RouteComponent,
  pendingComponent: PageSkeleton,
  validateSearch: (search: Record<string, unknown>) => {
    return {
      q: (search.q as string) ?? '',
      planId: (search.planId as string) ?? '',
      carreraId: (search.carreraId as string) ?? '',
      facultadId: (search.facultadId as string) ?? '',
      f: (search.f as 'sinBibliografia' | 'sinCriterios' | 'sinContenidos' | '') ?? '',
    }
  },
  loader: async ({ context: { queryClient }, location }) => {
    const search = (location?.search ?? {}) as SearchState
    // Pre-hydrate ambas queries con QueryClient (sin llamadas "sueltas" aquí)
    await Promise.all([
      queryClient.ensureQueryData(asignaturasOptions(search)),
      queryClient.ensureQueryData(planesOptions()),
    ])
    return null
  },
})

/* ================== Página ================== */
function RouteComponent() {
  const router = useRouter()
  const qc = useQueryClient()
  const search = Route.useSearch() as SearchState

  // Datos por TanStack Query (suspense-friendly)
  const { data: asignaturas } = useSuspenseQuery(asignaturasOptions(search))
  const { data: planes } = useSuspenseQuery(planesOptions())

  // Filtros
  const [q, setQ] = useState(search.q ?? '')
  const [sem, setSem] = useState<string>('todos')
  const [tipo, setTipo] = useState<string>('todos')
  const [groupBy] = useState<'semestre' | 'ninguno'>('semestre')
  const [flag, setFlag] = useState<'' | 'sinBibliografia' | 'sinCriterios' | 'sinContenidos'>(search.f ?? '')

  const [facultad, setFacultad] = useState("todas")
  const [carrera, setCarrera] = useState("todas")

  /* useEffect(() => {
    const timeout = setTimeout(() => {
      router.navigate({
        to: '/asignaturas',
        search: { ...search, q },
        replace: true,
      })
    }, 400)
    return () => clearTimeout(timeout)
  }, [q]) */


  function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
    const value = e.target.value
    setQ(value)
    router.navigate({
      to: '/asignaturas',
      search: {
        ...search,
        q: value,
      },
      replace: true, // evita recargar o empujar al historial
    })
  }

  // 🟣 Lista única de facultades
  const facultadesList = useMemo(() => {
    const unique = new Map<string, string>()
    planes?.forEach((p) => {
      const fac = p.carrera?.facultad
      if (fac?.id && fac?.nombre) unique.set(fac.id, fac.nombre)
    })
    return Array.from(unique.entries())
  }, [planes])

  // 🎓 Lista de carreras según la facultad seleccionada
  const carrerasList = useMemo(() => {
    const unique = new Map<string, string>()
    planes?.forEach((p) => {
      if (
        p.carrera?.id &&
        p.carrera?.nombre &&
        (!facultad || facultad === "todas" || p.carrera?.facultad?.id === facultad)
      ) {
        unique.set(p.carrera.id, p.carrera.nombre)
      }
    })
    return Array.from(unique.entries())
  }, [planes, facultad])


  // NEW: Clonado individual
  const [cloneOpen, setCloneOpen] = useState(false)
  const [cloneTarget, setCloneTarget] = useState<Asignatura | null>(null)
  const [cloneForm, setCloneForm] = useState<{
    nombre?: string
    clave?: string | null
    tipo?: string | null
    semestre?: number | null
    creditos?: number | null
    horas_teoricas?: number | null
    horas_practicas?: number | null
    plan_destino_id?: string | ''
  }>({})

  // NEW: Carrito
  const [cart, setCart] = useState<Asignatura[]>([])
  const [bulkOpen, setBulkOpen] = useState(false)
  const [bulk, setBulk] = useState<{
    plan_destino_id?: string | ''
    semestre?: string
    creditos?: string
    tipo?: string
  }>({})

  // Valores selects
  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])

  // Salud
  const salud = useMemo(() => {
    let sinBibliografia = 0, sinCriterios = 0, sinContenidos = 0
    for (const a of asignaturas) {
      if (!a.bibliografia || (Array.isArray(a.bibliografia) && a.bibliografia.length === 0)) sinBibliografia++
      if (!a.criterios_evaluacion || !a.criterios_evaluacion.trim()) sinCriterios++
      if (!a.contenidos || Object.keys(a.contenidos ?? {}).length === 0) sinContenidos++
    }
    return { sinBibliografia, sinCriterios, sinContenidos }
  }, [asignaturas])

  const filtered = useMemo(() => {
    const t = q.trim().toLowerCase()
    return asignaturas.filter(a => {
      const matchesQ =
        !t ||
        [a.nombre, a.clave, a.tipo, a.objetivos, a.plan?.nombre, a.plan?.carrera?.nombre, a.plan?.carrera?.facultad?.nombre]
          .filter(Boolean)
          .some(v => String(v).toLowerCase().includes(t))

      const semOK = sem === 'todos' || String(a.semestre ?? '—') === sem
      const tipoOK = tipo === 'todos' || (a.tipo ?? '—') === tipo
      const carreraOK = carrera === 'todas' || a.plan?.carrera?.id === carrera
      const facultadOK = facultad === 'todas' || a.plan?.carrera?.facultad?.id === facultad
      const planOK = !search.planId || a.plan?.id === search.planId

      const flagOK =
        !flag ||
        (flag === 'sinBibliografia' && (!a.bibliografia || a.bibliografia.length === 0)) ||
        (flag === 'sinCriterios' && (!a.criterios_evaluacion || !a.criterios_evaluacion.trim())) ||
        (flag === 'sinContenidos' && (!a.contenidos || Object.keys(a.contenidos ?? {}).length === 0))

      return matchesQ && semOK && tipoOK && flagOK && carreraOK && facultadOK && planOK
    })
  }, [q, sem, tipo, flag, carrera, facultad, asignaturas])


  // Agrupación
  const groups = useMemo(() => {
    if (groupBy === 'ninguno') return [['Todas', filtered] as [string, Asignatura[]]]
    const m = new Map<number | string, Asignatura[]>()
    for (const a of filtered) {
      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)
    })
  }, [filtered, groupBy])

  // Helpers
  const clearFilters = () => {
    setQ(''); setSem('todos'); setTipo('todos'); setCarrera('todas'); setFlag(''); setFacultad('todas')
    // Actualiza la URL limpiando todos los query params
    router.navigate({
      to: '/asignaturas',
      search: {
        q: '',
        planId: '',
        carreraId: '',
        facultadId: '',
        f: ''
      },
    })
  }

  // NEW: util para clonar 1 asignatura
  async function cloneOne(src: Asignatura, overrides: {
    plan_destino_id: string
    nombre?: string
    clave?: string | null
    tipo?: string | null
    semestre?: number | null
    creditos?: number | null
    horas_teoricas?: number | null
    horas_practicas?: number | null
  }) {
    if (!overrides.plan_destino_id) throw new Error('Selecciona un plan destino')

    const payload = {
      plan_id: overrides.plan_destino_id,
      nombre: overrides.nombre ?? src.nombre,
      clave: overrides.clave ?? src.clave,
      tipo: overrides.tipo ?? src.tipo,
      semestre: overrides.semestre ?? src.semestre,
      creditos: overrides.creditos ?? src.creditos,
      horas_teoricas: overrides.horas_teoricas ?? src.horas_teoricas,
      horas_practicas: overrides.horas_practicas ?? src.horas_practicas,
      objetivos: src.objetivos,
      contenidos: src.contenidos,
      bibliografia: src.bibliografia,
      criterios_evaluacion: src.criterios_evaluacion,
      estado: 'activo',
    }

    const { error } = await supabase.from('asignaturas').insert(payload)
    if (error) throw error
  }



  // NEW: abrir modal clon individual
  function openClone(a: Asignatura) {
    setCloneTarget(a)
    setCloneForm({
      nombre: a.nombre,
      clave: a.clave,
      tipo: a.tipo ?? '',
      semestre: a.semestre ?? undefined,
      creditos: a.creditos ?? undefined,
      horas_teoricas: a.horas_teoricas ?? undefined,
      horas_practicas: a.horas_practicas ?? undefined,
      plan_destino_id: a.plan?.id ?? '',
    })
    setCloneOpen(true)
  }

  // NEW: acciones carrito
  function addToCart(a: Asignatura) {
    setCart(prev => prev.find(x => x.id === a.id) ? prev : [...prev, a])
    toast.success('Asignatura añadida al carrito de asignaturas')
  }
  function removeFromCart(id: string) {
    setCart(prev => prev.filter(x => x.id !== id))
  }
  function clearCart() {
    setCart([])
  }



  // NEW: clonado en lote
  async function cloneBulk() {
    if (!bulk.plan_destino_id) { toast.error('Selecciona un plan de destino'); return }
    if (!cart.length) { toast.error('Carrito vacío'); return }

    try {
      const common: Partial<Asignatura> = {
        tipo: bulk.tipo && bulk.tipo !== '—' ? bulk.tipo : undefined,
        semestre: bulk.semestre ? Number(bulk.semestre) : undefined,
        creditos: bulk.creditos ? Number(bulk.creditos) : undefined,
      }

      for (const a of cart) {
        await cloneOne(a, {
          plan_destino_id: bulk.plan_destino_id!,
          tipo: common.tipo ?? undefined,
          semestre: common.semestre ?? undefined,
          creditos: common.creditos ?? undefined,
        })
      }
      toast.success(`Clonadas ${cart.length} asignaturas`)
      setBulkOpen(false)
      clearCart()
      // Invalida ambas queries y la ruta
      await Promise.all([
        qc.invalidateQueries({ queryKey: asignaturasKeys.root }),
        qc.invalidateQueries({ queryKey: planesKeys.root }),
      ])
      router.invalidate()
    } catch (e: any) {
      console.error(e)
      toast.error(e?.message || 'No se pudieron clonar')
    }
  }

  return (
    <div className="p-6 space-y-6">
      {/* HEADER */}
      <div className="rounded-3xl border bg-white/75 dark:bg-neutral-900/60 shadow-sm">
        <div className="p-5 flex flex-col gap-3">
          <div className="flex flex-wrap items-center justify-between gap-2">
            <h1 className="text-xl font-bold flex items-center gap-2 font-mono">
              <Icons.BookOpen className="w-5 h-5" />
              Asignaturas
            </h1>
            <div className="flex items-center gap-2">
              <Link
                to="/planes"
                className="hidden sm:inline-flex items-center gap-2 rounded-xl border px-3 py-2 text-sm hover:bg-neutral-50"
                search={{ plan: '' }}
              >
                <Icons.Plus className="w-4 h-4" /> Nueva asignatura
              </Link>
              {/* NEW: botón carrito */}
              <Button
                variant={cart.length ? 'default' : 'outline'}
                onClick={() => setBulkOpen(true)}
                className="relative"
              >
                <Icons.ShoppingCart className="w-4 h-4 mr-2" />
                Carrito de asignaturas
                {cart.length > 0 && (
                  <span className="ml-2 inline-flex h-5 min-w-[1.25rem] items-center justify-center rounded-full bg-white/90 text-[11px] text-neutral-900 px-1">
                    {cart.length}
                  </span>
                )}
              </Button>
              <Button variant="outline" size="icon" onClick={() => { qc.invalidateQueries({ queryKey: asignaturasKeys.root }); router.invalidate() }} title="Recargar">
                <Icons.RefreshCcw className="w-4 h-4" />
              </Button>
            </div>
          </div>

          {/* Filtros */}
          <div className="grid gap-4 sm:grid-cols-5 items-end">
            {/* 🔍 Búsqueda */}
            <div>
              <Label>Búsqueda</Label>
              <Input
                value={q}
                onChange={handleChange}
                placeholder="Nombre, clave, plan, carrera, facultad…"
              />
            </div>

            {/* 📘 Semestre */}
            <div>
              <Label>Semestre</Label>
              <Select value={sem} onValueChange={setSem}>
                <SelectTrigger>
                  <SelectValue placeholder="Todos" />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="todos">Todos</SelectItem>
                  {semestres.map((s) => (
                    <SelectItem key={s} value={s}>
                      Semestre {s}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>

            {/* 🏛️ Facultad */}
            <div>
              <Label>Facultad</Label>
              <Select
                value={facultad ?? "todas"}
                onValueChange={(val) => {
                  setFacultad(val)
                  setCarrera("todas")
                }}
              >
                <SelectTrigger className="w-[200px]">
                  <SelectValue placeholder="Filtrar por facultad" />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="todas">Todas las facultades</SelectItem>
                  {facultadesList.map(([id, nombre]) => (
                    <SelectItem key={id} value={id}>
                      {nombre}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>

            {/* 🎓 Carrera */}
            <div className={!facultad || facultad === "todas" ? "invisible" : ""}>
              <Label>Carrera</Label>
              <Select
                value={carrera ?? "todas"}
                onValueChange={(val) => setCarrera(val)}
              >
                <SelectTrigger className="w-[200px]">
                  <SelectValue placeholder="Filtrar por carrera" />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="todas">Todas las carreras</SelectItem>
                  {carrerasList.map(([id, nombre]) => (
                    <SelectItem key={id} value={id}>
                      {nombre}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>

            {/* 📜 Plan */}
            <div className={!carrera || carrera === "todas" ? "invisible" : ""}>
              <Label>Plan</Label>
              <Select
                value={search.planId ?? "todos"}
                onValueChange={(val) => {
                  router.navigate({
                    to: '/asignaturas',
                    search: {
                      ...search,
                      planId: val === 'todos' ? '' : val,
                    },
                    replace: true,
                  })
                }}
              >
                <SelectTrigger className="w-[200px]">
                  <SelectValue placeholder="Filtrar por plan" />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="todos">Todos los planes</SelectItem>
                  {planes
                    .filter((p) => p.carrera?.id === carrera)
                    .map((p) => (
                      <SelectItem key={p.id} value={p.id}>
                        {p.nombre}
                      </SelectItem>
                    ))}
                </SelectContent>
              </Select>
            </div>
          </div>




          {/* Chips de salud */}
          <div className="flex flex-wrap items-center gap-2">
            <HealthChip
              active={flag === 'sinBibliografia'}
              onClick={() => setFlag(flag === 'sinBibliografia' ? '' : 'sinBibliografia')}
              icon={<Icons.BookMarked className="w-3.5 h-3.5" />}
              label="Sin bibliografía"
              value={salud.sinBibliografia}
            />
            <HealthChip
              active={flag === 'sinCriterios'}
              onClick={() => setFlag(flag === 'sinCriterios' ? '' : 'sinCriterios')}
              icon={<Icons.ClipboardX className="w-3.5 h-3.5" />}
              label="Sin criterios de evaluación"
              value={salud.sinCriterios}
            />
            <HealthChip
              active={flag === 'sinContenidos'}
              onClick={() => setFlag(flag === 'sinContenidos' ? '' : 'sinContenidos')}
              icon={<Icons.ListX className="w-3.5 h-3.5" />}
              label="Sin contenidos"
              value={salud.sinContenidos}
            />
            {/*(q || sem !== 'todos' || tipo !== 'todos' || flag || carrera=='todos')*/ true && (
              <Button variant="ghost" className="h-7 px-3" onClick={clearFilters}>
                Limpiar filtros
              </Button>
            )}
          </div>
        </div>
      </div>

      {/* LISTA */}
      <div className="space-y-6">
        {!groups.length && <div className="text-sm text-neutral-500 text-center py-16">Sin asignaturas</div>}

        {groups.map(([key, items]) => (
          <section key={String(key)} className="space-y-2">
            {groupBy !== 'ninguno' && (
              <div className="sticky top-[64px] -mx-6 px-6 py-1 bg-background/90 backdrop-blur border-l-4 border-primary/30 text-xs font-semibold text-neutral-600 z-10">
                Semestre {key}
              </div>
            )}
            <ul className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
              {items.map(a => <AsignaturaCard key={a.id} a={a} onClone={() => openClone(a)} onAddToCart={() => addToCart(a)} />)}
            </ul>
          </section>
        ))}
      </div>

      {/* NEW: Modal clonado individual */}
      <Dialog open={cloneOpen} onOpenChange={setCloneOpen}>
        <DialogContent className="w-[min(92vw,720px)] sm:max-w-xl">
          <DialogHeader>
            <DialogTitle className="font-mono" >Clonar asignatura</DialogTitle>
          </DialogHeader>
          {cloneTarget && (
            <div className="grid gap-3">
              <div className="text-xs text-neutral-600">
                Origen: <strong>{cloneTarget.nombre}</strong> {cloneTarget.plan?.nombre ? `· ${cloneTarget.plan?.nombre}` : ''}
              </div>

              <div className="grid gap-3 sm:grid-cols-2">
                <div>
                  <Label>Nombre</Label>
                  <Input value={cloneForm.nombre ?? ''} onChange={e => setCloneForm(s => ({ ...s, nombre: e.target.value }))} />
                </div>
                <div>
                  <Label>Clave</Label>
                  <Input value={cloneForm.clave ?? ''} onChange={e => setCloneForm(s => ({ ...s, clave: e.target.value }))} />
                </div>
                <div>
                  <Label>Tipo</Label>
                  <Input value={cloneForm.tipo ?? ''} onChange={e => setCloneForm(s => ({ ...s, tipo: e.target.value }))} />
                </div>
                <div>
                  <Label>Créditos</Label>
                  <Input type="number" value={cloneForm.creditos ?? ''} onChange={e => setCloneForm(s => ({ ...s, creditos: e.target.value ? Number(e.target.value) : null }))} />
                </div>
                <div>
                  <Label>Semestre</Label>
                  <Input type="number" value={cloneForm.semestre ?? ''} onChange={e => setCloneForm(s => ({ ...s, semestre: e.target.value ? Number(e.target.value) : null }))} />
                </div>
                <div className="grid grid-cols-2 gap-2">
                  <div>
                    <Label>Horas T</Label>
                    <Input type="number" value={cloneForm.horas_teoricas ?? ''} onChange={e => setCloneForm(s => ({ ...s, horas_teoricas: e.target.value ? Number(e.target.value) : null }))} />
                  </div>
                  <div>
                    <Label>Horas P</Label>
                    <Input type="number" value={cloneForm.horas_practicas ?? ''} onChange={e => setCloneForm(s => ({ ...s, horas_practicas: e.target.value ? Number(e.target.value) : null }))} />
                  </div>
                </div>
                <div className="sm:col-span-2">
                  <Label>Plan destino</Label>
                  <Select value={cloneForm.plan_destino_id ?? ''} onValueChange={(v) => setCloneForm(s => ({ ...s, plan_destino_id: v }))}>
                    <SelectTrigger><SelectValue placeholder="Selecciona plan de estudios" /></SelectTrigger>
                    <SelectContent className="max-h-72">
                      {planes.map(p => (
                        <SelectItem key={p.id} value={p.id}>
                          {p.nombre} {p.carrera ? `· ${p.carrera.nombre}` : ''} {p.carrera?.facultad ? `· ${p.carrera.facultad.nombre}` : ''}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                </div>
              </div>
            </div>
          )}
          <DialogFooter>
            <Button variant="outline" onClick={() => setCloneOpen(false)}>Cancelar</Button>
            <Button
              onClick={async () => {
                if (!cloneTarget) return
                try {
                  await cloneOne(cloneTarget, {
                    plan_destino_id: (cloneForm.plan_destino_id as string) || '',
                    nombre: cloneForm.nombre,
                    clave: cloneForm.clave ?? null,
                    tipo: cloneForm.tipo ?? null,
                    semestre: (cloneForm.semestre as number) ?? null,
                    creditos: (cloneForm.creditos as number) ?? null,
                    horas_teoricas: (cloneForm.horas_teoricas as number) ?? null,
                    horas_practicas: (cloneForm.horas_practicas as number) ?? null,
                  })
                  toast.success('Asignatura clonada')
                  setCloneOpen(false)
                  await qc.invalidateQueries({ queryKey: asignaturasKeys.root })
                  router.invalidate()
                } catch (e: any) {
                  console.error(e)
                  toast.error(e?.message || 'No se pudo clonar')
                }
              }}
            >
              Clonar
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* NEW: Modal carrito */}
      <Dialog open={bulkOpen} onOpenChange={setBulkOpen}>
        <DialogContent className="w-[min(92vw,840px)]">
          <DialogHeader>
            <DialogTitle className="font-mono" >Carrito de asignaturas ({cart.length})</DialogTitle>
          </DialogHeader>

          {cart.length === 0 ? (
            <div className="text-sm text-neutral-500">No has añadido asignaturas. Usa el menú “…” de cada tarjeta.</div>
          ) : (
            <div className="space-y-4">
              <div className="rounded-xl border">
                <div className="grid grid-cols-12 px-3 py-2 text-[11px] font-medium text-neutral-600">
                  <div className="col-span-5">Asignatura</div>
                  <div className="col-span-2">Créditos</div>
                  <div className="col-span-2">Semestre</div>
                  <div className="col-span-2">Tipo</div>
                  <div className="col-span-1 text-right">—</div>
                </div>
                <ul className="divide-y">
                  {cart.map(a => (
                    <li key={a.id} className="grid grid-cols-12 items-center px-3 py-2 text-sm">
                      <div className="col-span-5">
                        <div className="font-medium">{a.nombre}</div>
                        <div className="text-[11px] text-neutral-500">{a.plan?.nombre} · {a.plan?.carrera?.nombre}</div>
                      </div>
                      <div className="col-span-2">{a.creditos ?? '—'}</div>
                      <div className="col-span-2">{a.semestre ?? '—'}</div>
                      <div className="col-span-2">{a.tipo ?? '—'}</div>
                      <div className="col-span-1 text-right">
                        <Button variant="ghost" size="icon" onClick={() => removeFromCart(a.id)}><Icons.X className="w-4 h-4" /></Button>
                      </div>
                    </li>
                  ))}
                </ul>
              </div>

              <div className="grid gap-3 sm:grid-cols-2">
                <div>
                  <Label>Plan de estudios destino</Label>
                  <Select value={bulk.plan_destino_id ?? ''} onValueChange={(v) => setBulk(s => ({ ...s, plan_destino_id: v }))}>
                    <SelectTrigger><SelectValue placeholder="Selecciona plan" /></SelectTrigger>
                    <SelectContent className="max-h-72">
                      {planes.map(p => (
                        <SelectItem key={p.id} value={p.id}>
                          {p.nombre} {p.carrera ? `· ${p.carrera.nombre}` : ''} {p.carrera?.facultad ? `· ${p.carrera.facultad.nombre}` : ''}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                </div>
                <div className="grid grid-cols-3 gap-3">
                  <div>
                    <Label>Créditos (común)</Label>
                    <Input
                      type="number"
                      placeholder="—"
                      value={bulk.creditos ?? ''}
                      onChange={e => setBulk(s => ({ ...s, creditos: e.target.value }))}
                    />
                  </div>
                  <div>
                    <Label>Semestre (común)</Label>
                    <Input
                      type="number"
                      placeholder="—"
                      value={bulk.semestre ?? ''}
                      onChange={e => setBulk(s => ({ ...s, semestre: e.target.value }))}
                    />
                  </div>
                  <div>
                    <Label>Tipo (común)</Label>
                    <Input
                      placeholder="Obligatoria / Optativa…"
                      value={bulk.tipo ?? ''}
                      onChange={e => setBulk(s => ({ ...s, tipo: e.target.value }))}
                    />
                  </div>
                </div>
              </div>

              <div className="flex items-center justify-between">
                <Button variant="ghost" onClick={clearCart}><Icons.Trash2 className="w-4 h-4 mr-1" /> Vaciar carrito de Asignaturas</Button>
                <div className="space-x-2">
                  <Button variant="outline" onClick={() => setBulkOpen(false)}>Cerrar</Button>
                  <Button onClick={cloneBulk}><Icons.CopyPlus className="w-4 h-4 mr-1" /> Clonar en lote</Button>
                </div>
              </div>
            </div>
          )}
        </DialogContent>
      </Dialog>
    </div>
  )
}

/* ================== Card ================== */
function tipoMeta(tipo?: string | null) {
  const t = (tipo ?? '').toLowerCase()
  if (t.includes('oblig')) return { label: 'Obligatoria', Icon: Icons.BadgeCheck, cls: 'bg-emerald-50 text-emerald-700 border-emerald-200' }
  if (t.includes('opt')) return { label: 'Optativa', Icon: Icons.Wand2, cls: 'bg-amber-50 text-amber-800 border-amber-200' }
  if (t.includes('taller')) return { label: 'Taller', Icon: Icons.Hammer, cls: 'bg-indigo-50 text-indigo-700 border-indigo-200' }
  if (t.includes('lab')) return { label: 'Laboratorio', Icon: Icons.FlaskConical, cls: 'bg-sky-50 text-sky-700 border-sky-200' }
  return { label: tipo ?? 'Genérica', Icon: Icons.BookOpen, cls: 'bg-neutral-100 text-neutral-700 border-neutral-200' }
}
function Chip({ children, className = '' }: { children: React.ReactNode; className?: string }) {
  return <span className={`inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[11px] ${className}`}>{children}</span>
}

function AsignaturaCard({ a, onClone, onAddToCart }: { a: Asignatura; onClone: () => void; onAddToCart: () => void }) {
  const horasT = a.horas_teoricas ?? 0
  const horasP = a.horas_practicas ?? 0
  const meta = tipoMeta(a.tipo)
  console.log(a);

  return (
    <li className="group relative overflow-hidden rounded-2xl border bg-white/75 dark:bg-neutral-900/60 shadow-sm hover:shadow-md transition-all"
      style={{
        borderColor: a.plan?.carrera?.facultad?.color ?? '#ccc',
        backgroundColor: `${a.plan?.carrera?.facultad?.color}15`, // 15 = transparencia HEX
      }}
    >
      <div className="p-3">
        <div className="flex items-start gap-3">
          <span className="mt-0.5 inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-xl border bg-white/80">
            <meta.Icon className="h-4 w-4" />
          </span>

          <div className="min-w-0 flex-1">
            <div className="flex items-start justify-between gap-2">
              <h4 className="font-mono leading-tight truncate" title={a.nombre}>{a.nombre}</h4>

              <DropdownMenu>
                <DropdownMenuTrigger asChild>
                  <Button variant="ghost" size="icon" className="mt-[-2px]"><Icons.MoreVertical className="w-4 h-4" /></Button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="end" className="min-w-[200px]">
                  <DropdownMenuItem asChild className="gap-2">
                    <Link to="/asignatura/$asignaturaId" params={{ asignaturaId: a.id }}>
                      <Icons.FolderOpen className="w-4 h-4" /> Abrir
                    </Link>
                  </DropdownMenuItem>
                  <DropdownMenuItem asChild className="gap-2">
                    <Link to="/plan/$planId" params={{ planId: a.plan?.id ?? '' }}>
                      <Icons.ScrollText className="w-4 h-4" /> Ver plan
                    </Link>
                  </DropdownMenuItem>
                  {/* NEW */}
                  <DropdownMenuItem className="gap-2" onClick={onClone}>
                    <Icons.Copy className="w-4 h-4" /> Clonar…
                  </DropdownMenuItem>
                  <DropdownMenuItem className="gap-2" onClick={onAddToCart}>
                    <Icons.ShoppingCart className="w-4 h-4" /> Añadir al carrito de asignaturas
                  </DropdownMenuItem>
                </DropdownMenuContent>
              </DropdownMenu>
            </div>

            <div className="mt-1 flex flex-wrap items-center gap-1.5 text-[11px]">
              {a.clave && <Chip className="bg-white/70"><Icons.KeyRound className="h-3 w-3" /> {a.clave}</Chip>}
              <Chip className={meta.cls}><meta.Icon className="h-3 w-3" /> {meta.label}</Chip>
              {a.creditos != null && <Chip className="bg-white/70"><Icons.Coins className="h-3 w-3" /> {a.creditos} créditos</Chip>}
              {(horasT + horasP) > 0 && <Chip className="bg-white/70"><Icons.Clock className="h-3 w-3" /> H T/P: {horasT}/{horasP}</Chip>}
              <Chip className="bg-white/70"><Icons.CalendarDays className="h-3 w-3" /> Semestre {a.semestre ?? '—'}</Chip>
            </div>

            {a.plan && (
              <div className="mt-2 flex flex-wrap items-center gap-2 text-[11px] text-neutral-600">
                <span className="inline-flex items-center gap-1">
                  <Icons.ScrollText className="w-3.5 h-3.5" /> <strong>Plan:</strong>{a.plan.nombre}
                </span>
                {a.plan.carrera && (
                  <InfoChip
                    icon={<Icons.GraduationCap className="h-3 w-3" />}
                    label={a.plan.carrera.nombre}
                  />
                )}
                {a.plan.carrera?.facultad && (
                  <InfoChip
                    icon={<Icons.Building2 className="h-3 w-3" />}
                    label={a.plan.carrera.facultad.nombre}
                    tint={a.plan.carrera.facultad.color}
                  />
                )}
              </div>
            )}

            <div className="mt-2 flex items-center justify-between">
              <p className="text-xs text-neutral-700 line-clamp-2">{a.objetivos ?? '—'}</p>
              <Link
                to="/asignatura/$asignaturaId"
                params={{ asignaturaId: a.id }}
                className="ml-3 inline-flex items-center gap-1 rounded-lg border px-3 py-1.5 text-xs hover:bg-neutral-50"
              >
                Ver <Icons.ArrowRight className="h-3.5 w-3.5" />
              </Link>
            </div>
          </div>
        </div>
      </div>
    </li>
  )
}

/* ================== UI helpers ================== */
function HealthChip({
  active, onClick, icon, label, value,
}: { active: boolean; onClick: () => void; icon: React.ReactNode; label: string; value: number }) {
  return (
    <button
      onClick={onClick}
      className={`inline-flex items-center gap-2 rounded-xl px-3 py-1.5 text-xs ring-1 transition-colors
        ${active
          ? 'bg-amber-50 text-amber-800 ring-amber-300'
          : 'bg-white/70 text-neutral-700 ring-neutral-200 hover:bg-neutral-50'}`}
    >
      {icon} {label}
      <span className={`ml-1 inline-flex h-5 min-w-[1.5rem] items-center justify-center rounded-full px-1 text-[11px]
        ${active ? 'bg-amber-100 text-amber-900' : 'bg-neutral-100 text-neutral-800'}`}>
        {value}
      </span>
    </button>
  )
}

/* ================== Skeleton ================== */
function Pulse({ className = '' }: { className?: string }) {
  return <div className={`animate-pulse bg-neutral-200 dark:bg-neutral-800 rounded-xl ${className}`} />
}
function PageSkeleton() {
  return (
    <div className="p-6 space-y-6">
      <Pulse className="h-36" />
      <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
        {Array.from({ length: 9 }).map((_, i) => <Pulse key={i} className="h-32" />)}
      </div>
    </div>
  )
}
