"use client";

import { use, useState, useMemo, useCallback } from "react";
import Link from "next/link";
import { clsx } from "clsx";
import { ArrowRight, MessageSquare, Trash2, Share2, Search, Sparkles, Loader2, AlertTriangle, Zap } from "lucide-react";
import { ShareVaultModal } from "@/components/share-vault-modal";
import { useVaults, useMemories, useConversations, useVaultContent, useActivityEvents } from "@/lib/use-data";
import { deleteMemory, updateIssue, addTagsToMemory, listComments, fetchDocument, fetchFileContent } from "@/lib/api";
import { summarizeConversation, isAIConfigured, checkMemoryHygiene, checkStaleness } from "@/lib/ai";
import type { Memory, Document as DocType, Skill, Folder, AttentionAlert } from "@/lib/types";
import { decodeVaultSlug, encodeVaultSlug } from "@/lib/types";
import { Breadcrumb } from "@/components/breadcrumb";
import { VaultOverviewPanel } from "@/components/vault-overview-panel";
import { MemoryCard } from "@/components/memory-card";
import { MemoryDetailPanel } from "@/components/memory-detail-panel";
import { MemoryFilterSidebar } from "@/components/memory-filter-sidebar";
import type { MemoryFilterState } from "@/components/memory-filter-sidebar";
import { FolderBrowser } from "@/components/folder-browser";
import { DocumentViewer } from "@/components/document-viewer";
import { DocumentCard, parseFrontmatter } from "@/components/document-card";
import { SkillCard } from "@/components/skill-card";
import { SkillDetail } from "@/components/skill-detail";
import { ActivityEventRow } from "@/components/activity-event";
import { ConversationViewer } from "@/components/conversation-viewer";
import { FileUploadZone } from "@/components/file-upload-zone";
import { TagEditor } from "@/components/tag-editor";
import { ConfirmationModal } from "@/components/confirmation-modal";
import { useToast } from "@/components/toast";

type Tab = "overview" | "memories" | "conversations" | "knowledge" | "skills";

function formatRelativeTime(dateStr: string): string {
  const now = Date.now();
  const then = new Date(dateStr).getTime();
  const diffMs = now - then;
  const diffMin = Math.floor(diffMs / 60000);
  if (diffMin < 1) return "just now";
  if (diffMin < 60) return `${diffMin}m ago`;
  const diffHr = Math.floor(diffMin / 60);
  if (diffHr < 24) return `${diffHr}h ago`;
  const diffDays = Math.floor(diffHr / 24);
  if (diffDays === 1) return "yesterday";
  return `${diffDays}d ago`;
}

export default function VaultDetailPage({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = use(params);
  const { owner, repo } = decodeVaultSlug(slug);
  const vaultFullName = `${owner}/${repo}`;

  // Refresh key for data re-fetching after mutations
  const [refreshKey, setRefreshKey] = useState(0);
  const triggerRefresh = useCallback(() => setRefreshKey((k) => k + 1), []);

  const { vaults, loading: vaultsLoading } = useVaults(refreshKey);
  const { events: allActivityEvents } = useActivityEvents(refreshKey);
  const vault = vaults.find((v) => v.fullName === vaultFullName);
  const { showToast } = useToast();

  const [activeTab, setActiveTab] = useState<Tab>("overview");
  const [showShareModal, setShowShareModal] = useState(false);

  // Memories
  const { memories, loading: memoriesLoading } = useMemories(vaultFullName, refreshKey);
  const [selectedMemory, setSelectedMemory] = useState<Memory | null>(null);
  const [memoryFilters, setMemoryFilters] = useState<MemoryFilterState>({
    status: "all",
    tags: [],
    sources: [],
    sort: "newest",
  });

  // Conversation delete state
  const [convToDelete, setConvToDelete] = useState<Memory | null>(null);
  const [deletingConv, setDeletingConv] = useState(false);

  // Conversation summarize state
  const [summarizingConvId, setSummarizingConvId] = useState<number | null>(null);

  // Memory hygiene state
  const [hygieneChecking, setHygieneChecking] = useState(false);
  const [hygieneOpen, setHygieneOpen] = useState(false);
  const [hygieneResult, setHygieneResult] = useState<{
    duplicates: { ids: string[]; explanation: string }[];
    contradictions: { ids: string[]; explanation: string }[];
  } | null>(null);

  // Staleness check state
  const [stalenessChecking, setStalenessChecking] = useState(false);
  const [stalenessResults, setStalenessResults] = useState<Record<string, { isStale: boolean; reasons: string[]; summary: string }>>({});

  // Conversations
  const { conversations, loading: convsLoading } = useConversations(vaultFullName, refreshKey);
  const [selectedConversation, setSelectedConversation] = useState<Memory | null>(null);

  // Documents & Skills (unified scan)
  const { documents, skills, loading: contentLoading } = useVaultContent(vaultFullName, refreshKey);
  const docsLoading = contentLoading;
  const skillsLoading = contentLoading;
  const [currentPath, setCurrentPath] = useState("");
  const [viewingDoc, setViewingDoc] = useState<DocType | null>(null);
  const [knowledgeSearch, setKnowledgeSearch] = useState("");

  // Lazy content loading state
  const [loadingDocContent, setLoadingDocContent] = useState(false);
  const [loadingSkillContent, setLoadingSkillContent] = useState(false);

  // Open a document — fetch full content lazily if needed (meta cache path)
  const openDocument = useCallback(async (doc: DocType) => {
    if (doc.content) {
      setViewingDoc(doc);
      return;
    }
    // Content not loaded yet (from meta cache) — fetch it
    setLoadingDocContent(true);
    setViewingDoc(doc); // show viewer immediately with loading state
    try {
      const fullDoc = await fetchDocument(vaultFullName, doc.path);
      if (fullDoc) {
        setViewingDoc(fullDoc);
      }
    } catch {
      // Keep the empty-content doc visible; viewer will show empty
    } finally {
      setLoadingDocContent(false);
    }
  }, [vaultFullName]);

  // Select a skill — fetch full content lazily if needed (meta cache path)
  const selectSkill = useCallback(async (skill: Skill) => {
    if (skill.content) {
      setSelectedSkill(skill);
      return;
    }
    // Content not loaded yet (from meta cache) — fetch it
    setLoadingSkillContent(true);
    setSelectedSkill(skill); // show detail immediately
    try {
      const content = await fetchFileContent(vaultFullName, skill.entryPath);
      if (content !== null) {
        setSelectedSkill({ ...skill, content });
      }
    } catch {
      // Keep the empty-content skill visible
    } finally {
      setLoadingSkillContent(false);
    }
  }, [vaultFullName]);

  // Skills selection
  const [selectedSkill, setSelectedSkill] = useState<Skill | null>(null);

  // Computed: all unique tags and sources from actual memory data
  const allTags = useMemo(() => {
    const tagSet = new Set<string>();
    memories.forEach((m) => m.tags.forEach((t) => tagSet.add(t)));
    return Array.from(tagSet).sort();
  }, [memories]);

  const allSources = useMemo(() => {
    const sourceSet = new Set<string>();
    memories.forEach((m) => { if (m.source) sourceSet.add(m.source); });
    return Array.from(sourceSet).sort();
  }, [memories]);

  // Filtered and sorted memories
  const filteredMemories = useMemo(() => {
    let result = [...memories];
    if (memoryFilters.status !== "all") {
      result = result.filter((m) => m.status === memoryFilters.status);
    }
    if (memoryFilters.tags.length > 0) {
      result = result.filter((m) =>
        memoryFilters.tags.some((t) => m.tags.includes(t))
      );
    }
    if (memoryFilters.sources.length > 0) {
      result = result.filter((m) =>
        memoryFilters.sources.includes(m.source as "conversation" | "task" | "observation" | "upload")
      );
    }
    switch (memoryFilters.sort) {
      case "oldest":
        result.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
        break;
      case "importance":
        result.sort((a, b) => b.importance - a.importance);
        break;
      case "newest":
      default:
        result.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
        break;
    }
    return result;
  }, [memories, memoryFilters]);

  // Computed: folders and documents for current path
  const { folders, pathDocs } = useMemo(() => {
    const folderMap = new Map<string, { count: number; lastMod: string }>();
    const pathDocs: DocType[] = [];

    for (const doc of documents) {
      if (currentPath === "") {
        // Root: extract top-level folder names from doc.folder
        const parts = doc.folder.split("/").filter(Boolean);
        if (parts.length > 0) {
          const topFolder = parts[0];
          const existing = folderMap.get(topFolder);
          if (!existing) {
            folderMap.set(topFolder, { count: 1, lastMod: doc.lastModified });
          } else {
            existing.count++;
            if (new Date(doc.lastModified) > new Date(existing.lastMod)) {
              existing.lastMod = doc.lastModified;
            }
          }
        } else {
          pathDocs.push(doc);
        }
      } else {
        if (doc.folder === currentPath) {
          pathDocs.push(doc);
        } else if (doc.folder.startsWith(currentPath + "/")) {
          const remaining = doc.folder.slice(currentPath.length + 1);
          const nextFolder = remaining.split("/")[0];
          const fullPath = currentPath + "/" + nextFolder;
          const existing = folderMap.get(fullPath);
          if (!existing) {
            folderMap.set(fullPath, { count: 1, lastMod: doc.lastModified });
          } else {
            existing.count++;
            if (new Date(doc.lastModified) > new Date(existing.lastMod)) {
              existing.lastMod = doc.lastModified;
            }
          }
        }
      }
    }

    const folders: Folder[] = Array.from(folderMap.entries()).map(([path, data]) => ({
      name: path.split("/").pop() || path,
      path,
      documentCount: data.count,
      lastModified: data.lastMod,
    }));

    return { folders, pathDocs };
  }, [documents, currentPath]);

  // Compute alerts from vault data
  const vaultAlerts = useMemo<AttentionAlert[]>(() => {
    if (!vault) return [];
    const alerts: AttentionAlert[] = [];
    if (vault.fadingCount > 0) {
      alerts.push({
        id: `fading-${vault.fullName}`,
        severity: "warning",
        message: `${vault.fadingCount} fading memor${vault.fadingCount === 1 ? "y" : "ies"} need${vault.fadingCount === 1 ? "s" : ""} review`,
        vaultFullName: vault.fullName,
        actionLabel: "Review",
        actionUrl: `/vaults/${slug}?status=fading`,
      });
    }
    return alerts;
  }, [vault, slug]);

  // Filter activity events for this vault
  const vaultEvents = useMemo(() => {
    return allActivityEvents
      .filter((e) => e.location.fullName === vaultFullName)
      .slice(0, 5);
  }, [allActivityEvents, vaultFullName]);

  // Handle conversation delete
  const handleDeleteConversation = useCallback(async () => {
    if (!convToDelete) return;
    setDeletingConv(true);
    try {
      const success = await deleteMemory(vaultFullName, convToDelete.id);
      if (success) {
        showToast("Conversation deleted", "success");
        setConvToDelete(null);
        triggerRefresh();
      } else {
        showToast("Failed to delete conversation", "error");
      }
    } catch {
      showToast("Failed to delete conversation", "error");
    } finally {
      setDeletingConv(false);
    }
  }, [convToDelete, vaultFullName, showToast, triggerRefresh]);

  // Handle conversation summarize
  const handleSummarizeConversation = useCallback(async (conv: Memory) => {
    if (!isAIConfigured()) {
      showToast("AI not configured — set up in Settings", "error");
      return;
    }
    setSummarizingConvId(conv.id);
    try {
      const [o, r] = vaultFullName.split("/");
      const rawComments = await listComments(o, r, conv.id);
      if (!rawComments || !Array.isArray(rawComments) || rawComments.length === 0) {
        showToast("No messages to summarize", "error");
        setSummarizingConvId(null);
        return;
      }
      const messagesText = rawComments
        .map((c: any) => c.body || "")
        .join("\n---\n")
        .slice(0, 6000);

      const result = await summarizeConversation(messagesText);
      if (!result) {
        showToast("AI summarization failed", "error");
        setSummarizingConvId(null);
        return;
      }

      // Update the issue body with the summary
      await updateIssue(o, r, conv.id, { body: result.summary });

      // Add suggested tags as labels
      if (result.tags && result.tags.length > 0) {
        await addTagsToMemory(vaultFullName, conv.id, result.tags);
      }

      showToast("Conversation summarized", "success");
      triggerRefresh();
    } catch {
      showToast("Failed to summarize conversation", "error");
    } finally {
      setSummarizingConvId(null);
    }
  }, [vaultFullName, showToast, triggerRefresh]);

  // Handle memory hygiene check
  const handleHygieneCheck = useCallback(async () => {
    setHygieneChecking(true);
    try {
      const payload = memories.map((m) => ({ id: m.id, title: m.title, content: m.content }));
      const result = await checkMemoryHygiene(payload);
      if (result) {
        setHygieneResult(result);
        setHygieneOpen(true);
      } else {
        showToast("Hygiene check failed", "error");
      }
    } catch {
      showToast("Hygiene check failed", "error");
    } finally {
      setHygieneChecking(false);
    }
  }, [memories, showToast]);

  // Handle "Keep best" for duplicate group — keep first memory, delete rest
  const handleKeepBest = useCallback(async (ids: string[]) => {
    if (ids.length < 2) return;
    const toDelete = ids.slice(1);
    let deleted = 0;
    for (const idStr of toDelete) {
      const num = parseInt(idStr, 10);
      if (!isNaN(num)) {
        const ok = await deleteMemory(vaultFullName, num);
        if (ok) deleted++;
      }
    }
    if (deleted > 0) {
      showToast(`Removed ${deleted} duplicate${deleted > 1 ? "s" : ""}`, "success");
      triggerRefresh();
      // Refresh hygiene result by removing the resolved group
      if (hygieneResult) {
        setHygieneResult({
          ...hygieneResult,
          duplicates: hygieneResult.duplicates.filter((d) => d.ids.join(",") !== ids.join(",")),
        });
      }
    }
  }, [vaultFullName, showToast, triggerRefresh, hygieneResult]);

  // Handle staleness check for visible documents
  const handleStalenessCheck = useCallback(async () => {
    setStalenessChecking(true);
    const results: Record<string, { isStale: boolean; reasons: string[]; summary: string }> = {};
    try {
      // Check sessionStorage cache first
      const docsToCheck = pathDocs.filter((doc) => {
        const cacheKey = `knowhub_stale_${doc.path}`;
        try {
          const cached = sessionStorage.getItem(cacheKey);
          if (cached) {
            results[doc.path] = JSON.parse(cached);
            return false;
          }
        } catch { /* ignore */ }
        return true;
      });

      // For AI-configured: use AI check; otherwise use date-based fallback
      if (isAIConfigured()) {
        for (const doc of docsToCheck) {
          try {
            const res = await checkStaleness(doc.content, doc.lastModified, doc.name);
            if (res && res.results && res.results.length > 0) {
              const r = res.results[0];
              results[doc.path] = { isStale: r.isStale, reasons: r.reasons, summary: r.summary };
              try { sessionStorage.setItem(`knowhub_stale_${doc.path}`, JSON.stringify(results[doc.path])); } catch { /* ignore */ }
            }
          } catch { /* ignore individual failures */ }
        }
      } else {
        // Fallback: date-based check (> 6 months old)
        const sixMonthsAgo = Date.now() - 180 * 24 * 60 * 60 * 1000;
        for (const doc of docsToCheck) {
          const modTime = new Date(doc.lastModified).getTime();
          const isStale = modTime < sixMonthsAgo;
          results[doc.path] = {
            isStale,
            reasons: isStale ? [`Last modified over 6 months ago`] : [],
            summary: isStale ? "May need review based on age" : "Recently updated",
          };
          try { sessionStorage.setItem(`knowhub_stale_${doc.path}`, JSON.stringify(results[doc.path])); } catch { /* ignore */ }
        }
      }
      setStalenessResults(results);
    } catch {
      showToast("Staleness check failed", "error");
    } finally {
      setStalenessChecking(false);
    }
  }, [pathDocs, showToast]);

  // Vault not found (still loading or genuinely not found)
  if (vaultsLoading) {
    return (
      <div className="p-8">
        <Breadcrumb
          items={[
            { label: "Vaults", href: "/vaults" },
            { label: "Loading..." },
          ]}
        />
        <div className="flex flex-col items-center justify-center py-20 text-center">
          <p className="text-text-secondary">Loading vault...</p>
        </div>
      </div>
    );
  }

  if (!vault) {
    return (
      <div className="p-8">
        <Breadcrumb
          items={[
            { label: "Vaults", href: "/vaults" },
            { label: "Not Found" },
          ]}
        />
        <div className="flex flex-col items-center justify-center py-20 text-center">
          <p className="text-text-secondary mb-4">
            Vault &ldquo;{vaultFullName}&rdquo; not found.
          </p>
          <Link
            href="/vaults"
            className="text-sm text-accent hover:text-accent-hover transition-colors"
          >
            Back to vaults
          </Link>
        </div>
      </div>
    );
  }

  const tabs: { key: Tab; label: string }[] = [
    { key: "overview", label: "Overview" },
    { key: "memories", label: `Memories${memories.length ? ` (${memories.length})` : ''}` },
    { key: "conversations", label: `Conversations${conversations.length ? ` (${conversations.length})` : ''}` },
    { key: "knowledge", label: "Knowledge" },
    { key: "skills", label: "Skills" },
  ];

  return (
    <div className="p-8 max-w-[1200px]">
      <div className="flex items-center justify-between">
        <Breadcrumb
          items={[
            { label: "Vaults", href: "/vaults" },
            { label: vault.name },
          ]}
        />
        <button
          onClick={() => setShowShareModal(true)}
          className="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md border border-border text-text-secondary hover:text-text-primary hover:bg-surface transition-colors"
        >
          <Share2 size={13} />
          Share
        </button>
      </div>

      {/* Vault Overview (collapsible) */}
      <VaultOverviewPanel vault={vault} alerts={vaultAlerts} />

      {/* Share Modal */}
      <ShareVaultModal
        open={showShareModal}
        vaultName={vault.name}
        onClose={() => setShowShareModal(false)}
      />

      {/* Tab bar */}
      <div className="flex items-center gap-1 border-b border-border-light mb-6">
        {tabs.map((tab) => (
          <button
            key={tab.key}
            onClick={() => {
              setActiveTab(tab.key);
              if (tab.key !== "memories") setSelectedMemory(null);
              if (tab.key !== "knowledge") setViewingDoc(null);
              if (tab.key !== "skills") setSelectedSkill(null);
            }}
            className={clsx(
              "px-4 py-2.5 text-sm font-medium border-b-2 transition-colors -mb-px",
              activeTab === tab.key
                ? "border-accent text-text-primary"
                : "border-transparent text-text-secondary hover:text-text-primary"
            )}
          >
            {tab.label}
          </button>
        ))}
      </div>

      {/* =================== OVERVIEW TAB =================== */}
      {activeTab === "overview" && (
        <div className="grid grid-cols-[1fr_0.65fr] gap-6">
          {/* Left: Recent activity + Recent memories */}
          <div className="space-y-6">
            {/* Recent Memories */}
            <section>
              <div className="flex items-center justify-between mb-3">
                <h2 className="text-sm font-semibold text-text-primary uppercase tracking-wide">
                  Recent Memories
                </h2>
                <button
                  onClick={() => setActiveTab("memories")}
                  className="flex items-center gap-1 text-xs text-accent hover:text-accent-hover transition-colors"
                >
                  View All <ArrowRight size={12} />
                </button>
              </div>
              {memoriesLoading ? (
                <p className="text-sm text-text-secondary">Loading...</p>
              ) : memories.length === 0 ? (
                <p className="text-sm text-text-muted">No memories yet.</p>
              ) : (
                <div className="space-y-2">
                  {memories.slice(0, 3).map((memory) => (
                    <MemoryCard
                      key={memory.id}
                      memory={memory}
                      onSelect={() => setActiveTab("memories")}
                    />
                  ))}
                </div>
              )}
            </section>

            {/* Recent Documents */}
            <section>
              <div className="flex items-center justify-between mb-3">
                <h2 className="text-sm font-semibold text-text-primary uppercase tracking-wide">
                  Recent Documents
                </h2>
                <button
                  onClick={() => setActiveTab("knowledge")}
                  className="flex items-center gap-1 text-xs text-accent hover:text-accent-hover transition-colors"
                >
                  View All <ArrowRight size={12} />
                </button>
              </div>
              {docsLoading ? (
                <p className="text-sm text-text-secondary">Loading...</p>
              ) : documents.length === 0 ? (
                <p className="text-sm text-text-muted">No documents yet.</p>
              ) : (
                <div className="space-y-2">
                  {documents.slice(0, 3).map((doc) => (
                    <DocumentCard
                      key={doc.path}
                      document={doc}
                      onClick={() => {
                        openDocument(doc);
                        setActiveTab("knowledge");
                      }}
                    />
                  ))}
                </div>
              )}
            </section>

            {/* Recent Activity */}
            <section>
              <div className="flex items-center justify-between mb-3">
                <h2 className="text-sm font-semibold text-text-primary uppercase tracking-wide">
                  Recent Activity
                </h2>
                <Link
                  href={`/activity?vault=${slug}`}
                  className="flex items-center gap-1 text-xs text-accent hover:text-accent-hover transition-colors"
                >
                  View All <ArrowRight size={12} />
                </Link>
              </div>
              {vaultEvents.length > 0 ? (
                <div className="rounded-xl bg-surface border border-border-light divide-y divide-border-light">
                  {vaultEvents.map((event) => (
                    <div key={event.id} className="px-4">
                      <ActivityEventRow event={event} />
                    </div>
                  ))}
                </div>
              ) : (
                <div className="rounded-xl bg-surface border border-border-light px-4 py-8 text-center">
                  <p className="text-sm text-text-secondary">
                    No recent activity for this vault.
                  </p>
                </div>
              )}
            </section>
          </div>

          {/* Right: Skill summary + Shared Spaces */}
          <div className="space-y-6">
            {/* Skill Summary */}
            <section>
              <div className="flex items-center justify-between mb-3">
                <h2 className="text-sm font-semibold text-text-primary uppercase tracking-wide">
                  Skills
                </h2>
                <button
                  onClick={() => setActiveTab("skills")}
                  className="flex items-center gap-1 text-xs text-accent hover:text-accent-hover transition-colors"
                >
                  View All <ArrowRight size={12} />
                </button>
              </div>
              {skillsLoading ? (
                <p className="text-sm text-text-secondary">Loading...</p>
              ) : skills.length === 0 ? (
                <p className="text-sm text-text-muted">No skills yet.</p>
              ) : (
                <div className="space-y-2">
                  {skills.slice(0, 3).map((skill) => (
                    <SkillCard
                      key={skill.path}
                      skill={skill}
                      onClick={() => {
                        selectSkill(skill);
                        setActiveTab("skills");
                      }}
                    />
                  ))}
                </div>
              )}
            </section>

          </div>
        </div>
      )}

      {/* =================== MEMORIES TAB =================== */}
      {activeTab === "memories" && (
        <div>
          {/* Memory Hygiene Banner */}
          {memories.length >= 5 && isAIConfigured() && (
            <div className="mb-4">
              {!hygieneResult ? (
                <div className="flex items-center gap-3 px-4 py-3 rounded-lg bg-surface border border-border-light">
                  <Sparkles size={16} className="text-accent shrink-0" />
                  <span className="text-sm text-text-secondary flex-1">
                    You have {memories.length} memories. Check for duplicates and contradictions?
                  </span>
                  <button
                    onClick={handleHygieneCheck}
                    disabled={hygieneChecking}
                    className="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md bg-accent text-white hover:bg-accent-hover transition-colors disabled:opacity-50"
                  >
                    {hygieneChecking ? <Loader2 size={12} className="animate-spin" /> : <Sparkles size={12} />}
                    Check memory health
                  </button>
                </div>
              ) : hygieneOpen ? (
                <div className="rounded-lg bg-surface border border-border-light overflow-hidden">
                  <div className="flex items-center justify-between px-4 py-3 border-b border-border-light">
                    <h3 className="text-sm font-semibold text-text-primary flex items-center gap-1.5">
                      <Sparkles size={14} className="text-accent" />
                      Memory Health Report
                    </h3>
                    <button
                      onClick={() => setHygieneOpen(false)}
                      className="text-xs text-text-muted hover:text-text-primary transition-colors"
                    >
                      Dismiss
                    </button>
                  </div>
                  <div className="px-4 py-3 space-y-4">
                    {hygieneResult.duplicates.length === 0 && hygieneResult.contradictions.length === 0 ? (
                      <p className="text-sm text-text-secondary">All clear! No duplicates or contradictions found.</p>
                    ) : (
                      <>
                        {hygieneResult.duplicates.length > 0 && (
                          <div>
                            <h4 className="text-xs uppercase tracking-wider text-text-muted mb-2">
                              Duplicates found ({hygieneResult.duplicates.length})
                            </h4>
                            <div className="space-y-2">
                              {hygieneResult.duplicates.map((group, i) => {
                                const groupMemories = group.ids
                                  .map((id) => memories.find((m) => String(m.id) === id))
                                  .filter(Boolean);
                                return (
                                  <div key={i} className="p-3 rounded-md bg-surface-elevated border border-border-light">
                                    <p className="text-xs text-text-secondary mb-2">{group.explanation}</p>
                                    <div className="space-y-1 mb-2">
                                      {groupMemories.map((m) => m && (
                                        <div key={m.id} className="text-xs text-text-primary">
                                          #{m.id}: {m.title}
                                        </div>
                                      ))}
                                    </div>
                                    <button
                                      onClick={() => handleKeepBest(group.ids)}
                                      className="text-xs px-2 py-1 rounded bg-accent/10 text-accent hover:bg-accent/20 transition-colors"
                                    >
                                      Keep best
                                    </button>
                                  </div>
                                );
                              })}
                            </div>
                          </div>
                        )}
                        {hygieneResult.contradictions.length > 0 && (
                          <div>
                            <h4 className="text-xs uppercase tracking-wider text-text-muted mb-2">
                              Contradictions found ({hygieneResult.contradictions.length})
                            </h4>
                            <div className="space-y-2">
                              {hygieneResult.contradictions.map((pair, i) => {
                                const pairMemories = pair.ids
                                  .map((id) => memories.find((m) => String(m.id) === id))
                                  .filter(Boolean);
                                return (
                                  <div key={i} className="p-3 rounded-md bg-surface-elevated border border-border-light">
                                    <p className="text-xs text-text-secondary mb-2">{pair.explanation}</p>
                                    <div className="flex gap-3">
                                      {pairMemories.map((m) => m && (
                                        <div key={m.id} className="flex-1 text-xs p-2 rounded border border-border bg-surface">
                                          <span className="font-medium text-text-primary">#{m.id}:</span>{" "}
                                          <span className="text-text-secondary">{m.title}</span>
                                        </div>
                                      ))}
                                    </div>
                                  </div>
                                );
                              })}
                            </div>
                          </div>
                        )}
                      </>
                    )}
                  </div>
                </div>
              ) : (
                <button
                  onClick={() => setHygieneOpen(true)}
                  className="flex items-center gap-1.5 px-4 py-2 text-xs text-text-muted hover:text-text-primary transition-colors"
                >
                  <Sparkles size={12} className="text-accent" />
                  Show memory health report
                </button>
              )}
            </div>
          )}

        <div className="flex gap-6">
          {/* Filter sidebar */}
          <MemoryFilterSidebar
            filters={memoryFilters}
            onFiltersChange={setMemoryFilters}
            availableTags={allTags}
            availableSources={allSources}
          />

          {/* Memory stream */}
          <div className="flex-1 min-w-0">
            {memoriesLoading ? (
              <p className="text-sm text-text-secondary py-8 text-center">Loading memories...</p>
            ) : filteredMemories.length === 0 ? (
              <div className="text-center py-16">
                <p className="text-sm text-text-secondary mb-1">No memories match your filters.</p>
                <button
                  onClick={() =>
                    setMemoryFilters({ status: "all", tags: [], sources: [], sort: "newest" })
                  }
                  className="text-xs text-accent hover:text-accent-hover"
                >
                  Clear filters
                </button>
              </div>
            ) : (
              <div className="space-y-2">
                {filteredMemories.map((memory) => (
                  <MemoryCard
                    key={memory.id}
                    memory={memory}
                    onSelect={setSelectedMemory}
                    selected={selectedMemory?.id === memory.id}
                  />
                ))}
              </div>
            )}
          </div>

          {/* Detail panel */}
          <MemoryDetailPanel
            memory={selectedMemory}
            onClose={() => setSelectedMemory(null)}
            onMutate={() => {
              setSelectedMemory(null);
              triggerRefresh();
            }}
          />
        </div>
        </div>
      )}

      {/* =================== CONVERSATIONS TAB =================== */}
      {activeTab === "conversations" && (
        <div>
          {convsLoading ? (
            <p className="text-sm text-text-secondary py-8 text-center">Loading conversations...</p>
          ) : conversations.length === 0 ? (
            <div className="text-center py-16">
              <p className="text-sm text-text-secondary">No conversations recorded yet.</p>
            </div>
          ) : (
            <div className="space-y-3">
              {conversations.map((conv) => (
                <div
                  key={conv.id}
                  className="rounded-lg border border-border-light bg-surface p-4 hover:bg-surface-elevated transition-colors cursor-pointer"
                  onClick={() => setSelectedConversation(conv)}
                >
                  <div className="flex items-center justify-between mb-2">
                    <div className="flex items-center gap-2">
                      <MessageSquare size={14} className="text-accent" />
                      <h3 className="text-sm font-semibold text-text-primary">{conv.title}</h3>
                    </div>
                    <div className="flex items-center gap-2">
                      <span className="text-xs text-text-muted">{formatRelativeTime(conv.createdAt)}</span>
                      <button
                        onClick={(e) => {
                          e.stopPropagation();
                          handleSummarizeConversation(conv);
                        }}
                        disabled={summarizingConvId === conv.id}
                        className="p-1 rounded-md text-text-muted hover:text-accent hover:bg-surface transition-colors disabled:opacity-50"
                        aria-label="Summarize conversation"
                        title="Summarize with AI"
                      >
                        {summarizingConvId === conv.id ? (
                          <Loader2 size={14} className="animate-spin" />
                        ) : (
                          <Sparkles size={14} />
                        )}
                      </button>
                      <button
                        onClick={(e) => {
                          e.stopPropagation();
                          setConvToDelete(conv);
                        }}
                        className="p-1 rounded-md text-text-muted hover:text-error hover:bg-surface transition-colors"
                        aria-label="Delete conversation"
                      >
                        <Trash2 size={14} />
                      </button>
                    </div>
                  </div>
                  {conv.content && (
                    <p className="text-sm text-text-secondary">{conv.content}</p>
                  )}
                  <div className="flex items-center gap-2 mt-2">
                    <span className="text-xs text-text-muted">{conv.commentCount} messages</span>
                    {conv.agent && (
                      <span className="text-xs px-1.5 py-0.5 rounded bg-surface-elevated text-text-muted border border-border-light">agent:{conv.agent}</span>
                    )}
                  </div>
                  {/* Tag Editor */}
                  <div className="mt-2" onClick={(e) => e.stopPropagation()}>
                    <TagEditor
                      tags={conv.tags}
                      vaultFullName={vaultFullName}
                      issueNumber={conv.id}
                      onTagsChanged={triggerRefresh}
                    />
                  </div>
                </div>
              ))}
            </div>
          )}
          {selectedConversation && (
            <ConversationViewer
              conversation={selectedConversation}
              vaultFullName={vaultFullName}
              onClose={() => setSelectedConversation(null)}
            />
          )}
          <ConfirmationModal
            open={convToDelete !== null}
            title="Delete Conversation"
            description={`Are you sure you want to delete "${convToDelete?.title}"? This will close the underlying issue.`}
            confirmLabel={deletingConv ? "Deleting..." : "Delete"}
            confirmDisabled={deletingConv}
            onConfirm={handleDeleteConversation}
            onCancel={() => setConvToDelete(null)}
          />
        </div>
      )}

      {/* =================== LIBRARY TAB =================== */}
      {activeTab === "knowledge" && (
        <div>
          {viewingDoc ? (
            loadingDocContent && !viewingDoc.content ? (
              <div className="flex flex-col items-center justify-center py-20">
                <Loader2 size={24} className="animate-spin text-text-secondary mb-3" />
                <p className="text-sm text-text-secondary">Loading document...</p>
                <button
                  onClick={() => { setViewingDoc(null); setLoadingDocContent(false); }}
                  className="mt-3 text-xs text-accent hover:text-accent-hover transition-colors"
                >
                  Cancel
                </button>
              </div>
            ) : (
              <DocumentViewer
                document={viewingDoc}
                onClose={() => setViewingDoc(null)}
                onMutate={() => {
                  setViewingDoc(null);
                  triggerRefresh();
                }}
              />
            )
          ) : docsLoading ? (
            <p className="text-sm text-text-secondary py-8 text-center">Loading knowledge...</p>
          ) : (
            <>
              <FileUploadZone
                vaultFullName={vaultFullName}
                currentPath={currentPath ? `knowledge/${currentPath}` : 'knowledge'}
                onUploadComplete={triggerRefresh}
                label="Add Knowledge"
              />

              {/* Filter bar */}
              <div className="flex items-center gap-3 mb-4">
                <div className="flex-1 relative">
                  <Search size={14} className="absolute left-3 top-1/2 -translate-y-1/2 text-text-muted" />
                  <input
                    type="text"
                    value={knowledgeSearch}
                    onChange={(e) => setKnowledgeSearch(e.target.value)}
                    placeholder="Search documents..."
                    className="w-full pl-9 pr-3 py-2 rounded-md bg-surface border border-border text-sm text-text-primary placeholder:text-text-muted outline-none focus:border-accent transition-colors"
                  />
                </div>
                <button
                  onClick={handleStalenessCheck}
                  disabled={stalenessChecking}
                  className="flex items-center gap-1.5 px-3 py-2 text-xs font-medium rounded-md border border-border text-text-secondary hover:text-text-primary hover:bg-surface-elevated transition-colors disabled:opacity-50 shrink-0"
                  title="Check all visible documents for staleness"
                >
                  {stalenessChecking ? <Loader2 size={13} className="animate-spin" /> : <AlertTriangle size={13} />}
                  Check Freshness
                </button>
              </div>

              {/* Folders */}
              {folders.length > 0 && (
                <FolderBrowser
                  currentPath={currentPath}
                  folders={folders}
                  documents={[]}
                  onNavigateFolder={setCurrentPath}
                  onOpenDocument={openDocument}
                  onBack={() => {
                    const parts = currentPath.split("/").filter(Boolean);
                    parts.pop();
                    setCurrentPath(parts.join("/"));
                  }}
                  vaultSlug={slug}
                />
              )}

              {/* Document cards */}
              {(() => {
                const searchLower = knowledgeSearch.toLowerCase();
                const filtered = pathDocs.filter((doc) => {
                  // Search filter
                  if (searchLower) {
                    const fm = parseFrontmatter(doc.content);
                    const titleMatch = (fm?.title || doc.name).toLowerCase().includes(searchLower);
                    const descMatch = (fm?.description || "").toLowerCase().includes(searchLower);
                    const tagMatch = (fm?.tags || []).some(t => t.toLowerCase().includes(searchLower));
                    if (!titleMatch && !descMatch && !tagMatch) return false;
                  }
                  return true;
                });

                if (filtered.length === 0 && folders.length === 0) {
                  return (
                    <div className="text-center py-16">
                      <p className="text-sm text-text-secondary mb-1">
                        {knowledgeSearch
                          ? "No documents match your search."
                          : "Your knowledge base is empty."}
                      </p>
                      {knowledgeSearch && (
                        <button
                          onClick={() => setKnowledgeSearch("")}
                          className="text-xs text-accent hover:text-accent-hover"
                        >
                          Clear search
                        </button>
                      )}
                    </div>
                  );
                }

                return (
                  <div className="space-y-2">
                    {filtered.map((doc) => (
                      <DocumentCard
                        key={doc.path}
                        document={doc}
                        onClick={openDocument}
                        staleness={stalenessResults[doc.path] || null}
                      />
                    ))}
                  </div>
                );
              })()}
            </>
          )}
        </div>
      )}

      {/* =================== SKILLS TAB =================== */}
      {activeTab === "skills" && (
        <div>
          <FileUploadZone
            vaultFullName={vaultFullName}
            currentPath="skills"
            onUploadComplete={triggerRefresh}
            label="Add Skill"
          />
          {skillsLoading ? (
            <p className="text-sm text-text-secondary py-8 text-center">Loading skills...</p>
          ) : skills.length === 0 ? (
            <div className="text-center py-16">
              <p className="text-sm text-text-secondary mb-1">No skills defined yet.</p>
              <p className="text-xs text-text-muted">
                Skills are reusable procedures that can be executed.
              </p>
            </div>
          ) : (
            <div className="grid grid-cols-12 gap-6">
              {/* Left column: Bento grid of skill cards */}
              <div className={selectedSkill ? "col-span-7" : "col-span-12"}>
                <div className="grid grid-cols-2 gap-3">
                  {skills.map((skill, idx) => (
                    <SkillCard
                      key={skill.path}
                      skill={skill}
                      isFirst={idx === 0}
                      isSelected={selectedSkill?.path === skill.path}
                      onClick={selectSkill}
                    />
                  ))}
                </div>
              </div>

              {/* Right column: Skill detail panel (5 cols) — only when selected */}
              {selectedSkill && (
                <div className="col-span-5">
                  <div className="sticky top-6">
                    <SkillDetail
                      skill={selectedSkill}
                      vaultFullName={vaultFullName}
                      onDelete={() => setSelectedSkill(null)}
                      onMutate={triggerRefresh}
                    />
                  </div>
                </div>
              )}
            </div>
          )}
        </div>
      )}
    </div>
  );
}
