// routes/_authenticated/archivos.tsx
import { createFileRoute, useRouter } from "@tanstack/react-router"
import { useEffect, useMemo, useState } from "react"
import { supabase, useSupabaseAuth } 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 { Textarea } from "@/components/ui/textarea"
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"

type EdgeModule = "files" | "vectorStores" | "vectorStoreFiles"

interface VectorStore {
  id: string
  object: "vector_store"
  created_at: number
  name: string | null
  description?: string | null
  usage_bytes: number
  file_counts: {
    in_progress: number
    completed: number
    failed: number
    cancelled: number
    total: number
  }
  status: string
  last_active_at?: number | null
  metadata?: Record<string, any> | null
}

interface VectorStoreFile {
  id: string
  object: string
  created_at: number
  vector_store_id: string
  status: string
  usage_bytes: number
  last_error?: { code: string; message: string } | null
}

interface VectorStoreFileMeta {
  id: string
  user_id: string | null
  vector_store_id: string
  openai_file_id: string
  label: string | null
  tags: string[] | null
  created_at: string
}

type EdgeArgs = {
  module: EdgeModule
  action: string
  params?: Record<string, any>
}

async function callFilesAndVectorStoresApi<T = unknown>(
  args: EdgeArgs,
): Promise<T> {
  const { data, error } = await supabase.functions.invoke<any>(
    "files-and-vector-stores-api",
    {
      body: args,
    },
  )

  if (error) {
    console.error(error)
    throw error
  }

  const payload = data ?? {}
  if (payload.error) {
    const msg =
      typeof payload.error === "string"
        ? payload.error
        : payload.error.message ?? "Error en la función Edge"
    throw new Error(msg)
  }

  const result = payload.data !== undefined ? payload.data : payload
  return result as T
}

export const Route = createFileRoute("/_authenticated/archivos")({
  component: RouteComponent,
  loader: async () => {
    const stores = await callFilesAndVectorStoresApi<VectorStore[]>({
      module: "vectorStores",
      action: "list",
      params: {},
    })
    return stores ?? []
  },
})

/* ====== UI helpers ====== */

function StatusBadge({ status }: { status: string }) {
  const label =
    status === "completed"
      ? "Completado"
      : status === "in_progress"
      ? "Procesando"
      : status
  const base = "text-[10px] px-2 py-0.5 rounded-full border"
  if (status === "completed") {
    return (
      <span
        className={`${base} bg-emerald-50 text-emerald-700 border-emerald-200`}
      >
        {label}
      </span>
    )
  }
  if (status === "in_progress") {
    return (
      <span
        className={`${base} bg-amber-50 text-amber-800 border-amber-200`}
      >
        {label}
      </span>
    )
  }
  return (
    <span className={`${base} bg-neutral-50 text-neutral-700 border-neutral-200`}>
      {label}
    </span>
  )
}

/* ====== Página principal: lista repositorios (Vector Stores) ====== */

function RouteComponent() {
  const router = useRouter()
  const vectorStores = Route.useLoaderData() as VectorStore[]

  const [q, setQ] = useState("")
  const [statusFilter, setStatusFilter] = useState<"all" | "completed" | "in_progress">("all")
  const [selected, setSelected] = useState<VectorStore | null>(null)
  const [dialogOpen, setDialogOpen] = useState(false)
  const [createOpen, setCreateOpen] = useState(false)
  const [deletingId, setDeletingId] = useState<string | null>(null)

  const filtered = useMemo(() => {
    const term = q.trim().toLowerCase()
    return vectorStores.filter((vs) => {
      if (statusFilter !== "all" && vs.status !== statusFilter) return false
      if (!term) return true
      return (
        (vs.name ?? "").toLowerCase().includes(term) ||
        (vs.description ?? "").toLowerCase().includes(term)
      )
    })
  }, [vectorStores, q, statusFilter])

  function openDetails(vs: VectorStore) {
    setSelected(vs)
    setDialogOpen(true)
  }

  async function handleDelete(id: string) {
    if (!confirm("¿Eliminar este repositorio y sus archivos asociados en OpenAI?")) return
    setDeletingId(id)
    try {
      await callFilesAndVectorStoresApi({
        module: "vectorStores",
        action: "delete",
        params: { id },
      })

      await supabase
        .from("vector_store_files_meta")
        .delete()
        .eq("vector_store_id", id)

      router.invalidate()
    } catch (err: any) {
      alert(err?.message ?? "Error al eliminar el repositorio")
    } finally {
      setDeletingId(null)
    }
  }

  return (
    <div className="p-6 space-y-4">
      <Card>
        <CardHeader className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
          <CardTitle className="font-mono">Repositorios de archivos</CardTitle>

          <div className="flex w-full flex-col gap-2 sm:w-auto sm:flex-row sm:items-center">
            <div className="relative w-full sm: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 descripción…"
                className="pl-8"
              />
            </div>

            <Select
              value={statusFilter}
              onValueChange={(v) =>
                setStatusFilter(v as "all" | "completed" | "in_progress")
              }
            >
              <SelectTrigger className="sm:w-[160px]">
                <SelectValue placeholder="Estado" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="all">Todos</SelectItem>
                <SelectItem value="completed">Completados</SelectItem>
                <SelectItem value="in_progress">En proceso</SelectItem>
              </SelectContent>
            </Select>

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

        <CardContent>
          {filtered.length ? (
            <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
              {filtered.map((vs) => (
                <article
                  key={vs.id}
                  className="rounded-2xl border bg-white/70 dark:bg-neutral-900/60 p-4 flex flex-col gap-3"
                >
                  <header className="min-w-0 space-y-1">
                    <div className="flex items-center justify-between gap-2">
                      <h3 className="font-semibold truncate">
                        {vs.name || "(Sin nombre)"}
                      </h3>
                      <StatusBadge status={vs.status} />
                    </div>
                    <div className="flex flex-wrap items-center gap-2 text-xs text-neutral-600">
                      <Badge variant="outline">
                        Archivos: {vs.file_counts?.completed ?? 0}
                      </Badge>
                      {typeof vs.usage_bytes === "number" && (
                        <span>
                          {(vs.usage_bytes / 1024 / 1024).toFixed(2)} MB
                        </span>
                      )}
                      {vs.last_active_at && (
                        <span className="inline-flex items-center gap-1">
                          <Icons.Clock3 className="w-3 h-3" />
                          {new Date(vs.last_active_at * 1000).toLocaleDateString()}
                        </span>
                      )}
                    </div>
                  </header>

                  {vs.description && (
                    <p className="text-sm text-neutral-700 line-clamp-3">
                      {vs.description}
                    </p>
                  )}

                  <div className="mt-auto flex items-center justify-between gap-2 pt-2">
                    <Button variant="ghost" size="sm" onClick={() => openDetails(vs)}>
                      <Icons.Eye className="w-4 h-4 mr-1" /> Abrir
                    </Button>
                    <Button
                      variant="ghost"
                      size="sm"
                      onClick={() => handleDelete(vs.id)}
                      disabled={deletingId === vs.id}
                    >
                      <Icons.Trash2 className="w-4 h-4 mr-1" />
                      {deletingId === vs.id ? "Eliminando…" : "Eliminar"}
                    </Button>
                  </div>
                </article>
              ))}
            </div>
          ) : (
            <div className="text-center text-sm text-neutral-500 py-10">
              No hay repositorios todavía. Crea uno nuevo para empezar 🚀
            </div>
          )}
        </CardContent>
      </Card>

      <CreateVectorStoreDialog
        open={createOpen}
        onOpenChange={setCreateOpen}
        onCreated={() => router.invalidate()}
      />

      <VectorStoreDialog
        store={selected}
        open={dialogOpen}
        onOpenChange={(open) => {
          setDialogOpen(open)
          if (!open) setSelected(null)
        }}
        onUpdated={() => router.invalidate()}
      />
    </div>
  )
}

/* ====== Crear repositorio ====== */

function CreateVectorStoreDialog({
  open,
  onOpenChange,
  onCreated,
}: {
  open: boolean
  onOpenChange: (open: boolean) => void
  onCreated: () => void
}) {
  const [name, setName] = useState("")
  const [description, setDescription] = useState("")
  const [creating, setCreating] = useState(false)

  async function handleCreate() {
    if (!name.trim()) {
      alert("Escribe un nombre para el repositorio")
      return
    }
    setCreating(true)
    try {
      await callFilesAndVectorStoresApi<VectorStore>({
        module: "vectorStores",
        action: "create",
        params: { name: name.trim(), description: description.trim() || undefined },
      })
      onOpenChange(false)
      setName("")
      setDescription("")
      onCreated()
    } catch (err: any) {
      alert(err?.message ?? "Error al crear el repositorio")
    } finally {
      setCreating(false)
    }
  }

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-w-md">
        <DialogHeader>
          <DialogTitle className="font-mono">Nuevo repositorio</DialogTitle>
          <DialogDescription>
            Crea un Vector Store para agrupar archivos relacionados.
          </DialogDescription>
        </DialogHeader>

        <div className="grid gap-3">
          <div className="space-y-1">
            <Label>Nombre</Label>
            <Input
              value={name}
              onChange={(e) => setName(e.target.value)}
              placeholder="Planeación curricular, Entrevistas…"
            />
          </div>
          <div className="space-y-1">
            <Label>Descripción (opcional)</Label>
            <Textarea
              value={description}
              onChange={(e) => setDescription(e.target.value)}
              placeholder="Breve descripción del contenido de este repositorio."
              className="min-h-[80px]"
            />
          </div>
        </div>

        <DialogFooter>
          <Button variant="outline" onClick={() => onOpenChange(false)}>
            Cancelar
          </Button>
          <Button onClick={handleCreate} disabled={creating || !name.trim()}>
            {creating ? "Creando…" : "Crear repositorio"}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}

/* ====== Detalle de un repositorio: archivos + subida ====== */

type FileRow = {
  file: VectorStoreFile
  meta: VectorStoreFileMeta | null
}

function VectorStoreDialog({
  store,
  open,
  onOpenChange,
  onUpdated,
}: {
  store: VectorStore | null
  open: boolean
  onOpenChange: (open: boolean) => void
  onUpdated: () => void
}) {
  const supabaseAuth = useSupabaseAuth()
  const [files, setFiles] = useState<FileRow[]>([])
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [uploading, setUploading] = useState(false)
  const [refreshing, setRefreshing] = useState(false)
  const [file, setFile] = useState<File | null>(null)
  const [label, setLabel] = useState("")

  useEffect(() => {
    if (!open || !store) return
    void refreshFiles()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open, store?.id])

  async function refreshFiles() {
    if (!store) return
    setLoading(true)
    setError(null)
    try {
      const vectorFiles = await callFilesAndVectorStoresApi<VectorStoreFile[]>({
        module: "vectorStoreFiles",
        action: "list",
        params: { vector_store_id: store.id },
      })

      const { data: metaRows, error: metaError } = await supabase
        .from("vector_store_files_meta")
        .select("*")
        .eq("vector_store_id", store.id)
        .order("created_at", { ascending: false })

      if (metaError) throw metaError

      const meta = (metaRows ?? []) as VectorStoreFileMeta[]

      const merged: FileRow[] = (vectorFiles ?? []).map((vf) => ({
        file: vf,
        meta: meta.find((m) => m.openai_file_id === vf.id) ?? null,
      }))

      setFiles(merged)
    } catch (err: any) {
      console.error(err)
      setError(err?.message ?? "No se pudieron cargar los archivos")
    } finally {
      setLoading(false)
    }
  }

  async function toBase64(f: File): Promise<string> {
    const buf = await f.arrayBuffer()
    const bytes = new Uint8Array(buf)
    let binary = ""
    for (let i = 0; i < bytes.byteLength; i++) {
      binary += String.fromCharCode(bytes[i])
    }
    return btoa(binary)
  }

  async function handleUpload() {
    if (!store || !file) {
      alert("Selecciona un archivo")
      return
    }
    setUploading(true)
    try {
      const fileBase64 = await toBase64(file)

      // 1) Subir archivo a OpenAI vía Edge (módulo files)
      const uploaded: any = await callFilesAndVectorStoresApi<any>({
        module: "files",
        action: "upload",
        params: {
          fileBase64,
          filename: file.name,
          mimeType: file.type,
        },
      })

      const openaiFileId: string =
        uploaded?.id ?? uploaded?.file?.id ?? uploaded?.data?.id

      if (!openaiFileId) {
        throw new Error("La Edge Function no devolvió el id del archivo")
      }

      // 2) Mapear archivo al Vector Store
      await callFilesAndVectorStoresApi<any>({
        module: "vectorStoreFiles",
        action: "create",
        params: {
          vector_store_id: store.id,
          file_id: openaiFileId,
        },
      })

      // 3) Guardar metadata en Supabase
      const { error: insertError } = await supabase
        .from("vector_store_files_meta")
        .insert({
          user_id: supabaseAuth.user?.id ?? null,
          vector_store_id: store.id,
          openai_file_id: openaiFileId,
          label: label.trim() || file.name,
        })

      if (insertError) throw insertError

      setFile(null)
      setLabel("")
      await refreshFiles()
      onUpdated()
    } catch (err: any) {
      console.error(err)
      alert(err?.message ?? "Error al subir el archivo")
    } finally {
      setUploading(false)
    }
  }

  async function handleDeleteFile(fileId: string) {
    if (!store) return
    if (!confirm("¿Eliminar este archivo del repositorio y de OpenAI?")) return
    setRefreshing(true)
    try {
      await callFilesAndVectorStoresApi<any>({
        module: "vectorStoreFiles",
        action: "delete",
        params: {
          vector_store_id: store.id,
          file_id: fileId,
        },
      })

      // Opcional: eliminar también el archivo global de OpenAI
      await callFilesAndVectorStoresApi<any>({
        module: "files",
        action: "delete",
        params: { id: fileId },
      })

      await supabase
        .from("vector_store_files_meta")
        .delete()
        .eq("openai_file_id", fileId)

      await refreshFiles()
      onUpdated()
    } catch (err: any) {
      console.error(err)
      alert(err?.message ?? "Error al eliminar el archivo")
    } finally {
      setRefreshing(false)
    }
  }

  if (!store) return null

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-w-2xl">
        <DialogHeader>
          <DialogTitle className="flex items-center gap-2">
            <Icons.Folder className="h-4 w-4" />
            {store.name || "(Sin nombre)"}
          </DialogTitle>
          <DialogDescription>
            Gestiona los archivos asociados a este repositorio (Vector Store).
          </DialogDescription>
        </DialogHeader>

        <div className="space-y-4">
          <div className="flex flex-wrap items-center gap-3 text-xs text-neutral-600">
            <StatusBadge status={store.status} />
            <Badge variant="outline">
              Archivos completados: {store.file_counts?.completed ?? 0}
            </Badge>
            <Badge variant="outline">
              Total archivos: {store.file_counts?.total ?? 0}
            </Badge>
            {typeof store.usage_bytes === "number" && (
              <span>{(store.usage_bytes / 1024 / 1024).toFixed(2)} MB</span>
            )}
          </div>

          {/* Subida de archivo */}
          <div className="space-y-2 rounded-lg border bg-muted/50 p-4">
            <Label className="text-xs font-semibold uppercase tracking-wide text-neutral-500">
              Agregar archivo al repositorio
            </Label>
            <div className="grid gap-3 sm:grid-cols-[minmax(0,1fr)_minmax(0,1fr)] sm:items-end">
              <div className="space-y-1">
                <Input
                  type="file"
                  accept=".pdf,.doc,.docx,.txt,.md"
                  onChange={(e) => setFile(e.target.files?.[0] ?? null)}
                />
                {file && (
                  <div className="text-xs text-neutral-600">
                    {file.name} · {(file.size / 1024).toFixed(1)} KB
                  </div>
                )}
              </div>
              <div className="space-y-1">
                <Label>Título / etiqueta</Label>
                <Input
                  value={label}
                  onChange={(e) => setLabel(e.target.value)}
                  placeholder="Ej.: Plan 2025, Entrevista 3…"
                />
                <Button
                  className="mt-2 w-full sm:w-auto"
                  onClick={handleUpload}
                  disabled={uploading || !file}
                >
                  {uploading ? "Subiendo…" : "Subir al repositorio"}
                </Button>
              </div>
            </div>
          </div>

          {/* Lista de archivos */}
          <div className="space-y-2">
            <div className="flex items-center justify-between">
              <Label>Archivos en este repositorio</Label>
              <Button
                variant="ghost"
                size="sm"
                onClick={() => refreshFiles()}
                disabled={loading || refreshing}
              >
                <Icons.RefreshCw className="h-4 w-4 mr-1" />
                Actualizar
              </Button>
            </div>

            {loading ? (
              <div className="text-xs text-neutral-500 py-4">
                Cargando archivos…
              </div>
            ) : error ? (
              <div className="text-xs text-red-500 py-4">{error}</div>
            ) : files.length === 0 ? (
              <div className="text-xs text-neutral-500 py-4">
                Todavía no hay archivos en este repositorio ⚡
              </div>
            ) : (
              <ul className="space-y-2 max-h-64 overflow-y-auto pr-1">
                {files.map(({ file, meta }) => (
                  <li
                    key={file.id}
                    className="flex items-center justify-between gap-3 rounded-md border bg-background px-3 py-2"
                  >
                    <div className="min-w-0">
                      <p className="font-medium truncate">
                        {meta?.label || file.id}
                      </p>
                      <p className="text-xs text-neutral-500 truncate">
                        {new Date(file.created_at * 1000).toLocaleString()} ·{" "}
                        {(file.usage_bytes / 1024).toFixed(1)} KB
                      </p>
                    </div>
                    <div className="flex items-center gap-2">
                      <StatusBadge status={file.status} />
                      <Button
                        variant="ghost"
                        size="icon"
                        onClick={() => handleDeleteFile(file.id)}
                      >
                        <Icons.Trash2 className="h-4 w-4" />
                      </Button>
                    </div>
                  </li>
                ))}
              </ul>
            )}
          </div>
        </div>

        <DialogFooter>
          <Button variant="outline" onClick={() => onOpenChange(false)}>
            Cerrar
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}
