import * as React from "react";
import { useTranslation } from "react-i18next";
import { NavLink, useNavigate, useParams } from "react-router-dom";
import {
  Archive,
  BarChart3,
  BookOpen,
  Bot,
  ClipboardCheck,
  Database,
  FilePlus,
  FileSearch,
  FileText,
  Filter,
  Gauge,
  Layers3,
  ListChecks,
  RefreshCw,
  RotateCcw,
  Search,
  Settings2,
  ShieldCheck,
  SlidersHorizontal,
  Sparkles,
  UploadCloud,
  type LucideIcon,
} from "lucide-react";
import {
  createKnowledgeBase,
  createKnowledgeDocument,
  getKnowledgeSettings,
  listKnowledgeIndexJobs,
  listKnowledgeBases,
  listKnowledgeChunks,
  listKnowledgeDocuments,
  listModels,
  parseKnowledgeDocument,
  reindexKnowledgeBase,
  searchKnowledge,
  updateKnowledgeSettings,
  updateKnowledgeBaseStatus,
} from "@/api";
import { translateApiError } from "@/api/errors";
import { ApiErrorState } from "@/components/shared/ApiErrorState";
import { EmptyState } from "@/components/shared/EmptyState";
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
import { MetricCard } from "@/components/shared/MetricCard";
import { PageHeader } from "@/components/shared/PageHeader";
import { SearchInput } from "@/components/shared/SearchInput";
import { StatusBadge } from "@/components/shared/StatusBadge";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Dialog } from "@/components/ui/dialog";
import { Input, Textarea } from "@/components/ui/input";
import { Select } from "@/components/ui/select";
import { Tabs } from "@/components/ui/tabs";
import { toast } from "@/components/ui/toaster";
import { demoText } from "@/lib/demo-text";
import { formatDateTime } from "@/lib/utils";
import type { JSONObject, KnowledgeBase, KnowledgeChunk, KnowledgeDocument, KnowledgeDocumentIngestResponse, KnowledgeDocumentParseResponse, KnowledgeIndexJob, ModelDefinition, SearchResult } from "@/types";
import type { KnowledgeSettingsPayload } from "@/api/knowledge";

const documentStatusValues = ["all", "queued", "indexing", "indexed", "draft", "failed", "archived"] as const;

const sourceTypeValues = ["all", "text", "markdown", "json", "html", "pdf"] as const;

type KnowledgeJob = {
  id: string;
  type: string;
  target: string;
  status: KnowledgeIndexJob["status"];
  progress: number;
  createdTime: string;
  workerKey?: string | null;
  errorMessage?: string | null;
};

type EvalCase = {
  id: string;
  query: string;
  expected: string;
  status: "draft" | "passed" | "failed";
  recall: number;
  precision: number;
};

type RetrievalConfig = {
  retrievalMode: string;
  embeddingModelId: string;
  rerankModelId: string;
  chunkSize: string;
  chunkOverlap: string;
  topK: string;
  minScore: string;
  maxCandidates: string;
  keywordWeight: string;
  vectorWeight: string;
  rerankWeight: string;
  queryRewrite: boolean;
  requireCitations: boolean;
};

const defaultRetrievalConfig: RetrievalConfig = {
  retrievalMode: "hybrid",
  embeddingModelId: "auto",
  rerankModelId: "auto",
  chunkSize: "800",
  chunkOverlap: "120",
  topK: "5",
  minScore: "0.20",
  maxCandidates: "50",
  keywordWeight: "0.30",
  vectorWeight: "0.55",
  rerankWeight: "0.15",
  queryRewrite: true,
  requireCitations: true,
};

const knowledgeSections = [
  { value: "overview", label: "Knowledge Bases", path: "/knowledge", icon: Database },
  { value: "documents", label: "Documents", path: "/knowledge/documents", icon: FileText },
  { value: "playground", label: "Test Search", path: "/knowledge/playground", icon: Search },
  { value: "evaluation", label: "Quality", path: "/knowledge/evaluation", icon: ClipboardCheck },
  { value: "jobs", label: "Index Jobs", path: "/knowledge/jobs", icon: ListChecks },
  { value: "analytics", label: "Analytics", path: "/knowledge/analytics", icon: BarChart3 },
  { value: "settings", label: "Settings", path: "/knowledge/settings", icon: Settings2 },
];

const capabilityGroups = [
  {
    titleKey: "knowledge.ingestion",
    icon: UploadCloud,
    items: [
      { labelKey: "knowledge.textMarkdownIngest", state: "live" },
      { labelKey: "knowledge.parsePreviewIng", state: "live" },
      { labelKey: "knowledge.pdfDocxHtmlParser", state: "prototype" },
      { labelKey: "knowledge.urlSitemapGithub", state: "prototype" },
    ],
  },
  {
    titleKey: "knowledge.indexingTab",
    icon: Layers3,
    items: [
      { labelKey: "knowledge.chunkSizeOverlap", state: "live" },
      { labelKey: "knowledge.embeddingModelTracking", state: "mock" },
      { labelKey: "knowledge.reindexDocumentBase", state: "prototype" },
      { labelKey: "knowledge.indexJobQueue", state: "prototype" },
    ],
  },
  {
    titleKey: "knowledge.retrievalTab",
    icon: Search,
    items: [
      { labelKey: "knowledge.hybridSearchPlayground", state: "live" },
      { labelKey: "knowledge.topKMetadataFilters", state: "live" },
      { labelKey: "knowledge.scoreBreakdownCitations", state: "live" },
      { labelKey: "knowledge.rerankQueryRewrite", state: "mock" },
    ],
  },
  {
    titleKey: "knowledge.evaluation",
    icon: ClipboardCheck,
    items: [
      { labelKey: "knowledge.goldenQueries", state: "prototype" },
      { labelKey: "knowledge.recallPrecisionMetrics", state: "prototype" },
      { labelKey: "knowledge.humanRelevanceFeedback", state: "prototype" },
      { labelKey: "knowledge.regressionComparison", state: "prototype" },
    ],
  },
  {
    titleKey: "knowledge.governance",
    icon: ShieldCheck,
    items: [
      { labelKey: "knowledge.archiveRestoreBase", state: "live" },
      { labelKey: "knowledge.documentAclPii", state: "prototype" },
      { labelKey: "knowledge.auditLog", state: "prototype" },
    ],
  },
  {
    titleKey: "knowledge.integration",
    icon: Bot,
    items: [
      { labelKey: "knowledge.agentBinding", state: "prototype" },
      { labelKey: "knowledge.workflowRetrievalNode", state: "prototype" },
      { labelKey: "knowledge.knowledgeSearchTool", state: "prototype" },
      { labelKey: "knowledge.runTraceCitations", state: "prototype" },
    ],
  },
];

export function KnowledgePage() {
  const { t } = useTranslation();
  const navigate = useNavigate();

  const documentStatusOptions = documentStatusValues.map((value) => ({
    value,
    label: t(`knowledge.statusLabels.${value}`),
  }));

  const sourceTypeOptions = sourceTypeValues.map((value) => ({
    value,
    label: t(`knowledge.sourceLabels.${value}`),
  }));
  const { section: sectionParam } = useParams();
  const section = knowledgeSections.some((item) => item.value === sectionParam) ? sectionParam ?? "overview" : "overview";
  const [bases, setBases] = React.useState<KnowledgeBase[]>([]);
  const [documents, setDocuments] = React.useState<KnowledgeDocument[]>([]);
  const [chunksByDocument, setChunksByDocument] = React.useState<Record<string, KnowledgeChunk[]>>({});
  const [models, setModels] = React.useState<ModelDefinition[]>([]);
  const [results, setResults] = React.useState<SearchResult[]>([]);
  const [selectedBaseId, setSelectedBaseId] = React.useState<string>();
  const [scopeMode] = React.useState<"current" | "all">("current");
  const [selectedDocumentId, setSelectedDocumentId] = React.useState<string>();
  const [baseSearch, setBaseSearch] = React.useState("");
  const [documentSearch, setDocumentSearch] = React.useState("");
  const [documentStatus, setDocumentStatus] = React.useState("all");
  const [sourceType, setSourceType] = React.useState("all");
  const [query, setQuery] = React.useState("");
  const [topK, setTopK] = React.useState("5");
  const [activeTab, setActiveTab] = React.useState("overview");
  const [loading, setLoading] = React.useState(true);
  const [documentsLoading, setDocumentsLoading] = React.useState(false);
  const [searching, setSearching] = React.useState(false);
  const [statusBusy, setStatusBusy] = React.useState(false);
  const [error, setError] = React.useState<string>();
  const [createOpen, setCreateOpen] = React.useState(false);
  const [documentOpen, setDocumentOpen] = React.useState(false);
  const [lastIngest, setLastIngest] = React.useState<KnowledgeDocumentIngestResponse>();
  const [jobs, setJobs] = React.useState<KnowledgeJob[]>([]);
  const [evalCases, setEvalCases] = React.useState<EvalCase[]>([]);
  const [retrievalConfig, setRetrievalConfig] = React.useState<RetrievalConfig>(defaultRetrievalConfig);

  const selectedBase = bases.find((base) => base.id === selectedBaseId);
  const selectedBases = scopeMode === "all" ? bases : selectedBase ? [selectedBase] : [];
  const activeBaseIds = scopeMode === "all" ? bases.map((base) => base.id) : selectedBaseId ? [selectedBaseId] : [];
  const activeBaseKey = activeBaseIds.join("|");
  const baseNameById = React.useMemo(() => new Map(bases.map((base) => [base.id, demoText(base.name, t)])), [bases, t]);
  const selectedDocument = documents.find((document) => document.id === selectedDocumentId);
  const sourceTypes = React.useMemo(() => Array.from(new Set(documents.map((document) => document.sourceType))).sort(), [documents]);
  const indexedCount = documents.filter((document) => document.status === "indexed").length;
  const filteredBases = bases.filter((base) => `${base.name} ${base.description ?? ""}`.toLowerCase().includes(baseSearch.toLowerCase()));
  const filteredDocuments = documents.filter((document) => {
    const matchesText = `${document.title} ${demoText(document.title, t)} ${document.sourceUri ?? ""} ${document.sourceType}`.toLowerCase().includes(documentSearch.toLowerCase());
    const matchesStatus = documentStatus === "all" || document.status === documentStatus;
    const matchesSource = sourceType === "all" || document.sourceType === sourceType;
    return matchesText && matchesStatus && matchesSource;
  });
  const selectedDocumentResults = selectedDocument
    ? results.filter((result) => result.document.id === selectedDocument.id || result.chunk.documentId === selectedDocument.id)
    : [];
  const selectedDocumentChunks = React.useMemo(() => {
    const chunks = [
      ...(selectedDocumentId ? chunksByDocument[selectedDocumentId] ?? [] : []),
      ...(lastIngest && lastIngest.document.id === selectedDocumentId ? lastIngest.chunks : []),
      ...results.filter((result) => result.chunk.documentId === selectedDocumentId).map((result) => result.chunk),
    ];
    return Array.from(new Map(chunks.map((chunk) => [chunk.id, chunk])).values());
  }, [chunksByDocument, lastIngest, results, selectedDocumentId]);

  const loadBases = React.useCallback(async () => {
    setLoading(true);
    setError(undefined);
    try {
      const data = await listKnowledgeBases();
      setBases(data);
      setSelectedBaseId((current) => current ?? data[0]?.id);
    } catch (err) {
      setError(translateApiError(err));
    } finally {
      setLoading(false);
    }
  }, [t]);

  const loadDocuments = React.useCallback(async (knowledgeBaseIds?: string[]) => {
    if (!knowledgeBaseIds?.length) {
      setDocuments([]);
      setChunksByDocument({});
      setResults([]);
      setSelectedDocumentId(undefined);
      return;
    }
    setDocumentsLoading(true);
    try {
      const [documentGroups, chunkGroups] = await Promise.all([
        Promise.all(knowledgeBaseIds.map((knowledgeBaseId) => listKnowledgeDocuments(knowledgeBaseId))),
        Promise.all(knowledgeBaseIds.map((knowledgeBaseId) => listKnowledgeChunks(knowledgeBaseId).catch(() => [] as KnowledgeChunk[]))),
      ]);
      const data = documentGroups.flat();
      setDocuments(data);
      setChunksByDocument(groupChunksByDocument(chunkGroups.flat()));
      setSelectedDocumentId((current) => (current && data.some((document) => document.id === current) ? current : data[0]?.id));
      setResults([]);
    } catch {
      setDocuments([]);
      setChunksByDocument({});
      setSelectedDocumentId(undefined);
      toast.error(t("knowledge.failedToLoadDocuments"));
    } finally {
      setDocumentsLoading(false);
    }
  }, [t]);

  const loadJobs = React.useCallback(async (knowledgeBaseIds?: string[]) => {
    if (!knowledgeBaseIds?.length) {
      setJobs([]);
      return;
    }
    try {
      const jobGroups = await Promise.all(knowledgeBaseIds.map((knowledgeBaseId) => listKnowledgeIndexJobs(knowledgeBaseId)));
      setJobs(jobGroups.flat().map(toKnowledgeJob));
    } catch {
      setJobs([]);
    }
  }, []);

  React.useEffect(() => {
    void loadBases();
  }, [loadBases]);

  React.useEffect(() => {
    let mounted = true;
    async function loadConfiguredModels() {
      try {
        const data = await listModels();
        if (mounted) setModels(data);
      } catch {
        if (mounted) setModels([]);
      }
    }
    void loadConfiguredModels();
    return () => {
      mounted = false;
    };
  }, []);

  React.useEffect(() => {
    void loadDocuments(activeBaseIds);
  }, [loadDocuments, activeBaseKey]);

  React.useEffect(() => {
    void loadJobs(activeBaseIds);
  }, [loadJobs, activeBaseKey]);

  React.useEffect(() => {
    let mounted = true;
    async function loadRetrievalSettings() {
      if (!selectedBaseId) {
        if (mounted) setRetrievalConfig(defaultRetrievalConfig);
        return;
      }
      try {
        const data = await getKnowledgeSettings(selectedBaseId);
        if (mounted) setRetrievalConfig(settingsPayloadToForm(data));
      } catch {
        if (mounted) setRetrievalConfig(defaultRetrievalConfig);
      }
    }
    void loadRetrievalSettings();
    return () => {
      mounted = false;
    };
  }, [selectedBaseId]);

  async function runSearch(event?: React.FormEvent) {
    event?.preventDefault();
    if (!activeBaseIds.length || !query.trim()) return;
    setSearching(true);
    try {
      const filters: JSONObject = {};
      if (documentStatus !== "all") filters.status = documentStatus;
      if (sourceType !== "all") filters.sourceType = sourceType;
      const data = (await Promise.all(activeBaseIds.map((baseId) => searchKnowledge(baseId, query.trim(), Number(topK) || 5, filters)))).flat();
      data.sort((a, b) => b.score - a.score);
      setResults(data);
      setActiveTab("search");
      if (section !== "playground") navigate("/knowledge/playground");
      toast.info(data.length ? t("knowledge.searchResults", { count: data.length }) : t("knowledge.noMatchingChunks"));
    } catch (err) {
      toast.error(translateApiError(err));
    } finally {
      setSearching(false);
    }
  }

  async function reloadSelectedBase() {
    await Promise.all([loadBases(), loadDocuments(activeBaseIds), loadJobs(activeBaseIds)]);
  }

  function selectBase(baseId: string) {
    setSelectedBaseId(baseId);
    setSelectedDocumentId(undefined);
  }

  async function toggleBaseStatus() {
    if (!selectedBase) return;
    setStatusBusy(true);
    try {
      const nextStatus = selectedBase.status === "active" ? "archived" : "active";
      const updated = await updateKnowledgeBaseStatus({ knowledgeBaseId: selectedBase.id, status: nextStatus });
      setBases((items) => items.map((base) => (base.id === updated.id ? updated : base)));
      toast.success(nextStatus === "active" ? t("knowledge.knowledgeBaseRestored") : t("knowledge.knowledgeBaseArchived"));
    } finally {
      setStatusBusy(false);
    }
  }

  async function createJobsForActiveBases(type: string) {
    const targets = selectedBases.length ? selectedBases : selectedBase ? [selectedBase] : [];
    for (const base of targets) {
      try {
        const result = await reindexKnowledgeBase({
          knowledgeBaseId: base.id,
          chunkSize: Number(retrievalConfig.chunkSize) || undefined,
          chunkOverlap: Number(retrievalConfig.chunkOverlap) || undefined,
        });
        setJobs((items) => [...result.jobs.map(toKnowledgeJob), ...items.filter((item) => !result.jobs.some((job) => job.jobId === item.id))]);
        toast.success(t("knowledge.createdJob", { type: formatKnowledgeJobType(type, t) }));
        await Promise.all([loadDocuments(activeBaseIds), loadJobs(activeBaseIds)]);
      } catch {
        toast.error(t("knowledge.documentIngestFailed"));
      }
    }
  }

  function addEvalCase(queryText: string, expected: string) {
    setEvalCases((items) => [
      { id: `eval_${Date.now().toString(36)}`, query: queryText, expected, status: "draft", recall: 0, precision: 0 },
      ...items,
    ]);
  }

  async function runEvalCase(evalId: string) {
    const item = evalCases.find((evalCase) => evalCase.id === evalId);
    if (!item || !activeBaseIds.length) return;
    const data = (await Promise.all(activeBaseIds.map((baseId) => searchKnowledge(baseId, item.query, Number(topK) || 5)))).flat();
    const expected = item.expected.toLowerCase();
    const matched = data.some((result) =>
      `${result.document.title} ${result.chunk.contentText}`.toLowerCase().includes(expected));
    const scoreAverage = average(data.map((result) => result.score));
    setEvalCases((items) =>
      items.map((evalCase) =>
        evalCase.id === evalId
          ? {
              ...evalCase,
              status: matched ? "passed" : "failed",
              recall: matched ? 1 : 0,
              precision: Number(Math.min(scoreAverage || 0, 1).toFixed(2)),
            }
          : evalCase));
    toast.success(t("knowledge.evaluationCaseFinished"));
  }

  function updateRetrievalConfig(nextConfig: RetrievalConfig) {
    setRetrievalConfig(nextConfig);
    if (!selectedBaseId) return;
    void updateKnowledgeSettings(formToSettingsPayload(nextConfig, selectedBaseId)).catch(() => {
      toast.error(t("common.failedToSave"));
    });
  }

  const isOverview = section === "overview";
  const pageTitle = isOverview ? t("knowledge.knowledgeBases") : demoText(selectedBase?.name, t) || t("knowledge.title");
  const pageDescription = isOverview
    ? t("knowledge.description")
    : t("knowledge.manageInsideBase");

  if (loading) return <LoadingSpinner label={t("knowledge.loading")} />;
  if (error) return <ApiErrorState message={error} onRetry={() => void loadBases()} />;

  return (
    <div className="space-y-6">
      <PageHeader
        title={pageTitle}
        description={pageDescription}
        actions={(
          <div className="flex flex-wrap gap-2">
            {!isOverview ? (
              <Button variant="secondary" onClick={() => navigate("/knowledge")}>
                <Database className="h-4 w-4" /> {t("knowledge.manageBases")}
              </Button>
            ) : null}
            {isOverview ? <Button onClick={() => setCreateOpen(true)}><BookOpen className="h-4 w-4" /> {t("knowledge.newBase")}</Button> : null}
            <Button size="icon" variant="ghost" aria-label={t("knowledge.refresh")} onClick={() => void reloadSelectedBase()}>
              <RefreshCw className="h-4 w-4" />
            </Button>
          </div>
        )}
      />

      {!isOverview ? (
        <>
          <KnowledgeScopeBar
            bases={bases}
            selectedBaseId={selectedBaseId}
            documentCount={documents.length}
            indexedCount={indexedCount}
            jobCount={jobs.length}
            onSelectBase={selectBase}
            onAddDocument={() => setDocumentOpen(true)}
            onTestSearch={() => navigate("/knowledge/playground")}
            onReindex={() => createJobsForActiveBases("Re-index")}
            onSettings={() => navigate("/knowledge/settings")}
          />
          <KnowledgeSectionNav />
        </>
      ) : null}

      {section === "overview" ? (
        <div className="space-y-6">
          <div className="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
            <MetricCard label={t("knowledge.knowledgeBases")} value={bases.length} icon={Database} />
            <MetricCard label={t("knowledge.documents")} value={documents.length} icon={FileText} />
            <MetricCard label={t("knowledge.indexed")} value={indexedCount} icon={Sparkles} />
            <MetricCard label={t("knowledge.sources")} value={sourceTypes.length} icon={Filter} />
          </div>
          <div className="grid gap-6 2xl:grid-cols-[minmax(280px,360px)_minmax(0,1fr)]">
            <KnowledgeBaseList
              bases={filteredBases}
              baseSearch={baseSearch}
              onSearch={setBaseSearch}
              selectedBaseId={selectedBaseId}
              onCreate={() => setCreateOpen(true)}
              onSelect={selectBase}
            />
            <div className="space-y-6">
              <BaseSummaryCard selectedBase={selectedBase} selectedBases={selectedBases} documents={documents} indexedCount={indexedCount} statusBusy={statusBusy} onToggleStatus={() => void toggleBaseStatus()} onOpenBase={() => navigate("/knowledge/documents")} />
              <KnowledgeCapabilityBoard compact />
            </div>
          </div>
        </div>
      ) : null}

      {section === "documents" ? (
        <div className="grid gap-6 2xl:grid-cols-[minmax(0,1fr)_420px]">
          <DocumentsPanel
            documentsLoading={documentsLoading}
            documents={documents}
            filteredDocuments={filteredDocuments}
            documentSearch={documentSearch}
            documentStatus={documentStatus}
            selectedDocumentId={selectedDocumentId}
            baseNameById={baseNameById}
            canAdd={Boolean(activeBaseIds.length)}
            onSearch={setDocumentSearch}
            onStatus={setDocumentStatus}
            onAdd={() => setDocumentOpen(true)}
            onSelect={(documentId) => {
              setSelectedDocumentId(documentId);
              setActiveTab("overview");
            }}
          />
          <DocumentInspector
            activeTab={activeTab}
            onTab={setActiveTab}
            selectedBase={selectedBase}
            selectedDocument={selectedDocument}
            selectedDocumentResults={selectedDocumentResults}
            selectedDocumentChunks={selectedDocumentChunks}
            lastIngest={lastIngest}
          />
        </div>
      ) : null}

      {section === "playground" ? (
        <div className="grid gap-6 2xl:grid-cols-[minmax(0,1fr)_420px]">
          <Card>
            <CardHeader>
              <CardTitle>{t("knowledge.retrievalPlayground")}</CardTitle>
              <p className="text-sm text-muted-foreground">
                {t("knowledge.askAgainstBase", { name: selectedBase?.name ?? t("knowledge.currentBase") })}
              </p>
            </CardHeader>
            <CardContent className="space-y-4">
              <form className="grid gap-3 xl:grid-cols-[minmax(0,1fr)_170px_140px] 2xl:grid-cols-[minmax(0,1fr)_170px_140px_auto]" onSubmit={(event) => void runSearch(event)}>
                <Input aria-label={t("knowledge.query")} value={query} onChange={(event) => setQuery(event.target.value)} placeholder={t("knowledge.askRetrievalQuestion")} />
                <Select aria-label={t("knowledge.searchSourceFilter")} value={sourceType} onChange={(event) => setSourceType(event.target.value)} options={sourceTypeOptions} />
                <Select aria-label="Top K" value={topK} onChange={(event) => setTopK(event.target.value)} options={[3, 5, 10, 20].map((value) => ({ value: String(value), label: `Top ${value}` }))} />
                <Button className="xl:col-span-3 2xl:col-span-1" disabled={!activeBaseIds.length || !query.trim() || searching}><Search className="h-4 w-4" /> {searching ? t("knowledge.searching") : t("knowledge.runSearch")}</Button>
              </form>
              {results.length ? <div className="space-y-3">{results.map((result) => <SearchResultCard key={result.chunk.id} result={result} />)}</div> : <EmptyState icon={Search} title={t("knowledge.noSearchResultsYet")} description={documents.length ? t("knowledge.runRetrievalInspect") : t("knowledge.addDocumentBeforeTest")} />}
            </CardContent>
          </Card>
          <RetrievalSettingsPanel config={retrievalConfig} models={models} onChange={updateRetrievalConfig} />
        </div>
      ) : null}

      {section === "evaluation" ? <EvaluationPage evalCases={evalCases} onAdd={addEvalCase} onRun={runEvalCase} /> : null}
      {section === "jobs" ? <JobsPage jobs={jobs} onCreateReindex={() => createJobsForActiveBases("Re-index")} /> : null}
      {section === "analytics" ? <AnalyticsPage documents={documents} results={results} jobs={jobs} evalCases={evalCases} /> : null}
      {section === "settings" ? (
        <div>
          <RetrievalSettingsPanel config={retrievalConfig} models={models} onChange={updateRetrievalConfig} />
        </div>
      ) : null}

      <CreateKnowledgeBaseDialog open={createOpen} onOpenChange={setCreateOpen} onCreated={() => void loadBases()} />
      <CreateKnowledgeDocumentDialog
        open={documentOpen}
        onOpenChange={setDocumentOpen}
        knowledgeBaseId={selectedBaseId ?? activeBaseIds[0]}
        knowledgeBaseName={baseNameById.get(selectedBaseId ?? activeBaseIds[0] ?? "")}
        onCreated={(ingest) => {
          setLastIngest(ingest);
          setChunksByDocument((current) => ({ ...current, [ingest.document.id]: ingest.chunks }));
          if (ingest.job) {
            setJobs((items) => [toKnowledgeJob(ingest.job!), ...items.filter((item) => item.id !== ingest.job?.jobId)]);
          }
          setSelectedDocumentId(ingest.document.id);
          setActiveTab("overview");
          void Promise.all([loadDocuments(activeBaseIds), loadJobs(activeBaseIds)]);
        }}
      />
    </div>
  );
}

function KnowledgeSectionNav() {
  const { t } = useTranslation();
  const workspaceSections = knowledgeSections.filter((item) => item.value !== "overview");
  return (
    <div className="overflow-x-auto rounded-md border border-border bg-surface-elevated p-1">
      <nav className="flex min-w-max gap-1">
        {workspaceSections.map((item) => (
          <NavLink
            key={item.value}
            to={item.path}
            className={({ isActive }) => [
              "inline-flex min-h-10 items-center gap-2 whitespace-nowrap rounded-sm px-3 text-sm text-muted-foreground transition hover:bg-muted hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-primary",
              isActive ? "bg-primary/15 text-primary" : "",
            ].join(" ")}
          >
            <item.icon className="h-4 w-4" />
            {t(`knowledge.sections.${item.value}`)}
          </NavLink>
        ))}
      </nav>
    </div>
  );
}

function KnowledgeScopeBar({
  bases,
  selectedBaseId,
  documentCount,
  indexedCount,
  jobCount,
  onSelectBase,
  onAddDocument,
  onTestSearch,
  onReindex,
  onSettings,
}: {
  bases: KnowledgeBase[];
  selectedBaseId?: string;
  documentCount: number;
  indexedCount: number;
  jobCount: number;
  onSelectBase: (baseId: string) => void;
  onAddDocument: () => void;
  onTestSearch: () => void;
  onReindex: () => void;
  onSettings: () => void;
}) {
  const { t } = useTranslation();
  const selectedBase = bases.find((base) => base.id === selectedBaseId);
  const hasBase = Boolean(selectedBase);
  return (
    <Card>
      <CardContent className="grid gap-4 p-4 2xl:grid-cols-[minmax(260px,360px)_minmax(0,1fr)_auto] 2xl:items-center">
        <div className="min-w-0">
          <p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">{t("knowledge.currentBase")}</p>
          <Select
            className="mt-2"
            value={selectedBaseId ?? ""}
            onChange={(event) => onSelectBase(event.target.value)}
            options={bases.map((base) => ({ value: base.id, label: demoText(base.name, t) }))}
          />
        </div>
        <div className="grid min-w-0 gap-2 sm:grid-cols-3">
          <ContextStat label={t("knowledge.documents")} value={documentCount} />
          <ContextStat label={t("knowledge.indexed")} value={indexedCount} />
          <ContextStat label={t("knowledge.jobs")} value={jobCount} />
        </div>
        <div className="flex min-w-0 flex-wrap gap-2 2xl:justify-end">
          <Button className="w-full sm:w-auto" size="sm" disabled={!hasBase} onClick={onAddDocument}>
            <FilePlus className="h-4 w-4" /> {t("knowledge.addDocument")}
          </Button>
          <Button className="w-full sm:w-auto" size="sm" variant="secondary" disabled={!hasBase} onClick={onTestSearch}>
            <Search className="h-4 w-4" /> {t("knowledge.testSearch")}
          </Button>
          <Button className="w-full sm:w-auto" size="sm" variant="secondary" disabled={!hasBase} onClick={onReindex}>
            <Layers3 className="h-4 w-4" /> {t("knowledge.reindex")}
          </Button>
          <Button className="w-11" size="icon" variant="ghost" disabled={!hasBase} aria-label={t("knowledge.openSettings")} onClick={onSettings}>
            <Settings2 className="h-4 w-4" />
          </Button>
        </div>
      </CardContent>
    </Card>
  );
}

function ContextStat({ label, value }: { label: string; value: number }) {
  return (
    <div className="min-w-0 rounded-md border border-border bg-muted/30 px-3 py-2">
      <p className="truncate text-xs text-muted-foreground">{label}</p>
      <p className="mt-1 font-mono text-sm font-semibold">{value}</p>
    </div>
  );
}

function KnowledgeBaseList({
  bases,
  baseSearch,
  selectedBaseId,
  onSearch,
  onSelect,
  onCreate,
}: {
  bases: KnowledgeBase[];
  baseSearch: string;
  selectedBaseId?: string;
  onSearch: (value: string) => void;
  onSelect: (baseId: string) => void;
  onCreate: () => void;
}) {
  const { t } = useTranslation();

  return (
    <Card>
      <CardHeader>
        <CardTitle>{t("knowledge.bases")}</CardTitle>
      </CardHeader>
      <CardContent className="space-y-4">
        <SearchInput value={baseSearch} onChange={onSearch} placeholder={t("knowledge.searchBases")} />
        {bases.length ? (
          <div className="space-y-2">
            {bases.map((base) => (
              <button
                key={base.id}
                type="button"
                onClick={() => onSelect(base.id)}
                className={[
                  "flex min-h-16 w-full items-center justify-between gap-3 rounded-md border border-border bg-muted/40 p-3 text-left transition hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-primary",
                  base.id === selectedBaseId ? "border-primary/40 bg-primary/10" : "",
                ].join(" ")}
              >
                <span className="min-w-0">
                  <span className="block truncate text-sm font-medium">{demoText(base.name, t)}</span>
                  {base.description ? <span className="mt-1 block truncate font-mono text-xs text-muted-foreground">{demoText(base.description, t)}</span> : null}
                </span>
                <span className="shrink-0"><StatusBadge status={base.status} /></span>
              </button>
            ))}
          </div>
        ) : (
          <EmptyState icon={BookOpen} title={t("knowledge.noBasesFound")} description={t("knowledge.createOrSearch")} actionLabel={t("knowledge.newBase")} onAction={onCreate} />
        )}
      </CardContent>
    </Card>
  );
}

function BaseSummaryCard({
  selectedBase,
  selectedBases,
  documents,
  indexedCount,
  statusBusy,
  onToggleStatus,
  onOpenBase,
}: {
  selectedBase?: KnowledgeBase;
  selectedBases: KnowledgeBase[];
  documents: KnowledgeDocument[];
  indexedCount: number;
  statusBusy: boolean;
  onToggleStatus: () => void;
  onOpenBase: () => void;
}) {
  const { t } = useTranslation();
  const title = selectedBases.length > 1
    ? t("knowledge.knowledgeBases_plural", { count: selectedBases.length })
    : demoText(selectedBase?.name, t) || t("knowledge.selectKnowledgeBase");
  return (
    <Card>
      <CardHeader>
        <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
          <div className="min-w-0">
            <CardTitle>{title}</CardTitle>
            <p className="mt-1 break-words text-sm text-muted-foreground">
              {selectedBases.length > 1 ? selectedBases.map((base) => demoText(base.name, t)).join(", ") : demoText(selectedBase?.description, t) || t("knowledge.chooseBaseManage")}
            </p>
          </div>
          <div className="flex flex-wrap gap-2 lg:justify-end">
            <Button className="w-full sm:w-auto" disabled={!selectedBase} onClick={onOpenBase}>
              <FileText className="h-4 w-4" /> {t("knowledge.openBase")}
            </Button>
            {selectedBase ? (
              <Button className="w-full sm:w-auto" variant="outline" disabled={statusBusy} onClick={onToggleStatus}>
                <Archive className="h-4 w-4" /> {selectedBase.status === "active" ? t("knowledge.archive") : t("knowledge.restoreCurrent")}
              </Button>
            ) : null}
          </div>
        </div>
      </CardHeader>
      <CardContent className="grid gap-3 sm:grid-cols-2 xl:grid-cols-4">
        <Detail label={t("knowledge.selected")} value={String(selectedBases.length || (selectedBase ? 1 : 0))} />
        <Detail label={t("common.status")} value={selectedBase ? t(`status.${selectedBase.status}`) : t("knowledge.notSelected")} />
        <Detail label={t("knowledge.documents")} value={String(documents.length)} />
        <Detail label={t("knowledge.indexed")} value={String(indexedCount)} />
      </CardContent>
    </Card>
  );
}

function DocumentsPanel({
  documentsLoading,
  documents,
  filteredDocuments,
  documentSearch,
  documentStatus,
  selectedDocumentId,
  baseNameById,
  canAdd,
  onSearch,
  onStatus,
  onAdd,
  onSelect,
}: {
  documentsLoading: boolean;
  documents: KnowledgeDocument[];
  filteredDocuments: KnowledgeDocument[];
  documentSearch: string;
  documentStatus: string;
  selectedDocumentId?: string;
  baseNameById: Map<string, string>;
  canAdd: boolean;
  onSearch: (value: string) => void;
  onStatus: (value: string) => void;
  onAdd: () => void;
  onSelect: (documentId: string) => void;
}) {
  const { t } = useTranslation();

  return (
    <Card>
      <CardHeader>
        <div className="flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
          <div className="min-w-0">
            <CardTitle>{t("knowledge.documents")}</CardTitle>
            <p className="mt-1 text-sm text-muted-foreground">{t("knowledge.documentsHint")}</p>
          </div>
          <div className="grid w-full min-w-0 gap-3 md:grid-cols-[minmax(0,1fr)_180px] 2xl:w-[720px] 2xl:grid-cols-[minmax(0,1fr)_180px_auto]">
            <SearchInput className="w-full sm:w-full" value={documentSearch} onChange={onSearch} placeholder={t("knowledge.searchDocuments")} />
            <Select aria-label={t("common.status")} value={documentStatus} onChange={(event) => onStatus(event.target.value)} options={documentStatusValues.map((value) => ({ value, label: t(`knowledge.statusLabels.${value}`) }))} />
            <Button className="md:col-span-2 2xl:col-span-1" variant="secondary" disabled={!canAdd} onClick={onAdd}><FilePlus className="h-4 w-4" /> {t("knowledge.addDocument")}</Button>
          </div>
        </div>
      </CardHeader>
      <CardContent>
        {documentsLoading ? (
          <LoadingSpinner label={t("knowledge.loadingDocuments")} />
        ) : filteredDocuments.length ? (
          <div className="grid gap-3 xl:grid-cols-2">
            {filteredDocuments.map((document) => (
              <button
                key={document.id}
                type="button"
                onClick={() => onSelect(document.id)}
                className={[
                  "min-h-28 rounded-md border p-4 text-left transition hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-primary",
                  document.id === selectedDocumentId ? "border-primary/50 bg-primary/10" : "border-border bg-muted/30",
                ].join(" ")}
              >
                <div className="flex items-start justify-between gap-3">
                  <div className="min-w-0">
                    <p className="truncate text-sm font-semibold">{demoText(document.title, t)}</p>
                    <p className="mt-1 truncate text-xs text-muted-foreground">
                      {baseNameById.get(document.knowledgeBaseId) ?? t("knowledge.title")} / {document.sourceUri || t(`knowledge.sourceLabels.${document.sourceType}`, humanizeCode(document.sourceType))}
                    </p>
                  </div>
                  <span className="shrink-0"><StatusBadge status={document.status} /></span>
                </div>
                <div className="mt-4 grid gap-3 text-xs text-muted-foreground sm:grid-cols-2">
                  <Detail label={t("knowledge.source")} value={t(`knowledge.sourceLabels.${document.sourceType}`, humanizeCode(document.sourceType))} />
                  <Detail label={t("knowledge.indexed")} value={document.indexedTime ? formatDateTime(document.indexedTime) : t("knowledge.pending")} />
                </div>
                <p className="mt-4 text-xs font-medium text-primary">{t("knowledge.openDetails")}</p>
              </button>
            ))}
          </div>
        ) : (
          <EmptyState
            icon={FileText}
            title={documents.length ? t("knowledge.noMatchingDocuments") : t("knowledge.noDocuments")}
            description={documents.length ? t("knowledge.adjustSearchOrStatus") : canAdd ? t("knowledge.addTextMarkdownJson") : t("knowledge.selectKnowledgeBaseFirst")}
            actionLabel={canAdd ? t("knowledge.addDocument") : undefined}
            onAction={canAdd ? onAdd : undefined}
          />
        )}
      </CardContent>
    </Card>
  );
}

function DocumentInspector({
  activeTab,
  onTab,
  selectedBase,
  selectedDocument,
  selectedDocumentResults,
  selectedDocumentChunks,
  lastIngest,
}: {
  activeTab: string;
  onTab: (value: string) => void;
  selectedBase?: KnowledgeBase;
  selectedDocument?: KnowledgeDocument;
  selectedDocumentResults: SearchResult[];
  selectedDocumentChunks: KnowledgeChunk[];
  lastIngest?: KnowledgeDocumentIngestResponse;
}) {
  const { t } = useTranslation();
  return (
    <Card className="min-w-0">
      <CardHeader>
        <CardTitle className="break-words">{selectedDocument ? demoText(selectedDocument.title, t) : t("knowledge.inspector")}</CardTitle>
      </CardHeader>
      <CardContent className="min-w-0">
        <Tabs
          value={activeTab}
          onChange={onTab}
          tabs={[
            {
              value: "overview",
              label: t("common.overview"),
              content: selectedDocument ? (
                <div className="space-y-4 text-sm">
                  <div className="grid gap-3 sm:grid-cols-2">
                    <Detail label={t("common.status")} value={t(`status.${selectedDocument.status}`, humanizeCode(selectedDocument.status))} />
                    <Detail label={t("knowledge.source")} value={t(`knowledge.sourceLabels.${selectedDocument.sourceType}`, humanizeCode(selectedDocument.sourceType))} />
                    <Detail label={t("common.created")} value={formatDateTime(selectedDocument.createdTime)} />
                    <Detail label={t("knowledge.indexed")} value={selectedDocument.indexedTime ? formatDateTime(selectedDocument.indexedTime) : t("knowledge.pending")} />
                  </div>
                  <Detail label={t("knowledge.sourceUri")} value={selectedDocument.sourceUri ?? t("knowledge.notProvided")} />
                  <Detail label={t("knowledge.contentHash")} value={selectedDocument.contentHash ?? t("knowledge.notAvailable")} />
                  {lastIngest?.document.id === selectedDocument.id ? (
                    <div className="rounded-md border border-green-500/25 bg-green-500/10 p-3 text-sm text-green-700 dark:text-green-200">
                      {t("knowledge.lastIngestCreated", { count: lastIngest.chunks.length })}
                    </div>
                  ) : null}
                </div>
              ) : (
                <EmptyState icon={FileText} title={t("knowledge.selectDocument")} description={t("knowledge.documentDetailsAppear")} />
              ),
            },
            {
              value: "search",
              label: t("knowledge.search"),
              content: selectedDocumentResults.length ? (
                <div className="space-y-3">{selectedDocumentResults.map((result) => <SearchResultCard key={result.chunk.id} result={result} />)}</div>
              ) : (
                <EmptyState icon={Search} title={t("knowledge.noDocumentSearchResults")} description={t("knowledge.runQueryPlayground")} />
              ),
            },
            {
              value: "metadata",
              label: t("knowledge.propertiesTab"),
              content: <MetadataSummary metadata={selectedDocument?.metadata ?? selectedBase?.metadata ?? {}} />,
            },
            {
              value: "chunks",
              label: t("knowledge.chunks"),
              content: selectedDocumentChunks.length ? (
                <div className="space-y-3">
                  {selectedDocumentChunks.map((chunk) => (
                    <div key={chunk.id} className="rounded-md border border-border bg-muted/30 p-3">
                      <div className="flex flex-wrap items-center justify-between gap-3">
                        <span className="font-mono text-xs text-muted-foreground">{t("knowledge.chunk")} #{chunk.chunkIndex}</span>
                        <span className="font-mono text-xs text-muted-foreground">{chunk.tokenCount} {t("knowledge.tokens")}</span>
                      </div>
                      <p className="mt-3 text-sm leading-6 text-muted-foreground">{chunk.contentText}</p>
                    </div>
                  ))}
                </div>
              ) : (
                <EmptyState icon={Layers3} title={t("knowledge.noChunksLoaded")} description={t("knowledge.runSearchOrIndex")} />
              ),
            },
          ]}
        />
      </CardContent>
    </Card>
  );
}

function EvaluationPage({ evalCases, onAdd, onRun }: { evalCases: EvalCase[]; onAdd: (queryText: string, expected: string) => void; onRun: (evalId: string) => void }) {
  const { t } = useTranslation();
  const [queryText, setQueryText] = React.useState("");
  const [expected, setExpected] = React.useState("");
  const avgRecall = average(evalCases.map((item) => item.recall));
  const avgPrecision = average(evalCases.map((item) => item.precision));

  function submit(event: React.FormEvent) {
    event.preventDefault();
    if (!queryText.trim()) return;
    onAdd(queryText.trim(), expected.trim() || t("knowledge.expectedCitation"));
    setQueryText("");
    setExpected("");
  }

  return (
    <div className="grid gap-6 2xl:grid-cols-[420px_minmax(0,1fr)]">
      <Card>
        <CardHeader>
          <CardTitle>{t("knowledge.goldenQuery")}</CardTitle>
          <p className="text-sm text-muted-foreground">{t("knowledge.buildEvaluationSet")}</p>
        </CardHeader>
        <CardContent>
          <form className="space-y-4" onSubmit={submit}>
            <Field label={t("knowledge.query")}><Textarea required value={queryText} onChange={(event) => setQueryText(event.target.value)} /></Field>
            <Field label={t("knowledge.expectedSource")}><Input value={expected} onChange={(event) => setExpected(event.target.value)} /></Field>
            <Button className="w-full"><ClipboardCheck className="h-4 w-4" /> {t("knowledge.addCase")}</Button>
          </form>
          <div className="mt-6 grid grid-cols-2 gap-3">
            <ScoreTile label={t("knowledge.avgRecall")} value={avgRecall} />
            <ScoreTile label={t("knowledge.avgPrecision")} value={avgPrecision} />
          </div>
        </CardContent>
      </Card>
      <Card>
        <CardHeader>
          <CardTitle>{t("knowledge.evaluationCases")}</CardTitle>
        </CardHeader>
        <CardContent className="space-y-3">
          {evalCases.map((item) => (
            <div key={item.id} className="rounded-md border border-border bg-muted/30 p-4">
              <div className="flex items-start justify-between gap-3">
                <div className="min-w-0">
                  <p className="break-words text-sm font-medium">{formatEvalText(item.query, t)}</p>
                  <p className="mt-1 break-words text-xs text-muted-foreground">{t("knowledge.expected")}: {formatEvalText(item.expected, t)}</p>
                </div>
                <span className="shrink-0"><StatusBadge status={item.status} /></span>
              </div>
              <div className="mt-4 grid gap-3 xl:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto]">
                <BarMeter label={t("knowledge.recall")} value={item.recall} />
                <BarMeter label={t("knowledge.precision")} value={item.precision} />
                <Button className="w-full xl:w-auto" size="sm" variant="secondary" onClick={() => onRun(item.id)}><RotateCcw className="h-4 w-4" /> {t("common.run")}</Button>
              </div>
            </div>
          ))}
        </CardContent>
      </Card>
    </div>
  );
}

function JobsPage({ jobs, onCreateReindex }: { jobs: KnowledgeJob[]; onCreateReindex: () => void }) {
  const { t } = useTranslation();

  return (
    <Card>
      <CardHeader>
        <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
          <div>
            <CardTitle>{t("knowledge.indexJobs")}</CardTitle>
            <p className="text-sm text-muted-foreground">{t("knowledge.manageFrontendQueues")}</p>
          </div>
          <Button className="w-full sm:w-auto" onClick={onCreateReindex}><RefreshCw className="h-4 w-4" /> {t("knowledge.reindexBase")}</Button>
        </div>
      </CardHeader>
      <CardContent className="space-y-3">
        {jobs.map((job) => (
          <div key={job.id} className="rounded-md border border-border bg-muted/30 p-4">
            <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
              <div className="min-w-0">
                <div className="flex flex-wrap items-center gap-2">
                  <p className="break-words text-sm font-semibold">{formatKnowledgeJobType(job.type, t)}</p>
                  <StatusBadge status={job.status} />
                </div>
                <p className="mt-1 break-words text-xs text-muted-foreground">{formatKnowledgeJobTarget(job.target, t)} / {formatDateTime(job.createdTime)}</p>
              </div>
            </div>
            <div className="mt-4">
              <BarMeter label={t("knowledge.progress")} value={job.progress / 100} />
            </div>
          </div>
        ))}
      </CardContent>
    </Card>
  );
}

function AnalyticsPage({ documents, results, jobs, evalCases }: { documents: KnowledgeDocument[]; results: SearchResult[]; jobs: KnowledgeJob[]; evalCases: EvalCase[] }) {
  const { t } = useTranslation();
  const failedJobs = jobs.filter((job) => job.status === "failed").length;
  const avgScore = average(results.map((result) => result.score));
  const indexedRatio = documents.length ? documents.filter((document) => document.status === "indexed").length / documents.length : 0;
  const passRatio = evalCases.length ? evalCases.filter((item) => item.status === "passed").length / evalCases.length : 0;

  return (
    <div className="space-y-6">
      <div className="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
        <MetricCard label={t("knowledge.indexedRatio")} value={`${Math.round(indexedRatio * 100)}%`} icon={Sparkles} />
        <MetricCard label={t("knowledge.avgScore")} value={avgScore ? avgScore.toFixed(2) : "0.00"} icon={Gauge} />
        <MetricCard label={t("knowledge.evalPass")} value={`${Math.round(passRatio * 100)}%`} icon={ClipboardCheck} />
        <MetricCard label={t("knowledge.failedJobs")} value={failedJobs} icon={BarChart3} />
      </div>
      <Card>
        <CardHeader>
          <CardTitle>{t("knowledge.qualitySignals")}</CardTitle>
        </CardHeader>
        <CardContent className="grid gap-4 md:grid-cols-2">
          <BarMeter label={t("knowledge.indexCoverage")} value={indexedRatio} />
          <BarMeter label={t("knowledge.citationConfidence")} value={avgScore || 0} />
          <BarMeter label={t("knowledge.evaluationPassRate")} value={passRatio} />
          <BarMeter label={t("knowledge.jobHealth")} value={jobs.length ? 1 - failedJobs / jobs.length : 1} />
        </CardContent>
      </Card>
      <Card>
        <CardHeader>
          <CardTitle>{t("knowledge.topQueries")}</CardTitle>
        </CardHeader>
        <CardContent className="grid gap-3 md:grid-cols-2">
          {["downloadInvoice", "refundPolicy", "billingContact", "planUpgrade"].map((item, index) => (
            <div key={item} className="rounded-md border border-border bg-muted/30 p-4">
              <p className="text-sm font-medium">{t(`knowledge.topQuery.${item}`)}</p>
              <p className="mt-1 font-mono text-xs text-muted-foreground">
                {t("knowledge.queryStats", { count: 42 - index * 7, rate: Math.round((0.91 - index * 0.06) * 100) })}
              </p>
            </div>
          ))}
        </CardContent>
      </Card>
    </div>
  );
}

function ToggleRow({ icon: Icon, title, description, checked, onChange }: { icon: LucideIcon; title: string; description: string; checked: boolean; onChange: (checked: boolean) => void }) {
  return (
    <label className="flex min-h-16 cursor-pointer items-start justify-between gap-4 rounded-md border border-border bg-muted/20 p-3">
      <span className="flex min-w-0 gap-3">
        <Icon className="mt-0.5 h-4 w-4 shrink-0 text-muted-foreground" />
        <span className="min-w-0">
          <span className="block text-sm font-medium">{title}</span>
          <span className="mt-1 block text-xs leading-5 text-muted-foreground">{description}</span>
        </span>
      </span>
      <input type="checkbox" className="mt-1 h-5 w-5 shrink-0 accent-primary" checked={checked} onChange={(event) => onChange(event.target.checked)} />
    </label>
  );
}

function BarMeter({ label, value }: { label: string; value: number }) {
  const normalized = Math.max(0, Math.min(1, value || 0));
  return (
    <div>
      <div className="flex items-center justify-between gap-3">
        <p className="text-xs text-muted-foreground">{label}</p>
        <p className="font-mono text-xs text-foreground">{Math.round(normalized * 100)}%</p>
      </div>
      <div className="mt-2 h-2 overflow-hidden rounded-full bg-muted">
        <div className="h-full rounded-full bg-primary" style={{ width: `${normalized * 100}%` }} />
      </div>
    </div>
  );
}

function ScoreTile({ label, value }: { label: string; value: number }) {
  return (
    <div className="rounded-md border border-border bg-muted/30 p-3">
      <p className="text-xs text-muted-foreground">{label}</p>
      <p className="mt-1 font-mono text-xl font-semibold">{Math.round(value * 100)}%</p>
    </div>
  );
}

function average(values: number[]) {
  const useful = values.filter((value) => value > 0);
  return useful.length ? useful.reduce((sum, value) => sum + value, 0) / useful.length : 0;
}

function groupChunksByDocument(chunks: KnowledgeChunk[]) {
  return chunks.reduce<Record<string, KnowledgeChunk[]>>((groups, chunk) => {
    groups[chunk.documentId] = [...(groups[chunk.documentId] ?? []), chunk].sort((a, b) => a.chunkIndex - b.chunkIndex);
    return groups;
  }, {});
}

function KnowledgeCapabilityBoard({ compact = false }: { compact?: boolean }) {
  const { t } = useTranslation();

  return (
    <Card>
      <CardHeader>
        <div className="flex flex-col gap-2 lg:flex-row lg:items-center lg:justify-between">
          <div>
            <CardTitle>{t("knowledge.knowledgeCapabilityMap")}</CardTitle>
            <p className="mt-1 text-sm text-muted-foreground">
              {compact ? t("knowledge.moduleStatusAtGlance") : t("knowledge.fullRagSurface")}
            </p>
          </div>
          <div className="flex flex-wrap gap-2">
            <StateBadge state="live" />
            <StateBadge state="mock" />
            <StateBadge state="prototype" />
          </div>
        </div>
      </CardHeader>
      <CardContent>
        <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
          {capabilityGroups.map((group) => (
            <div key={group.titleKey} className="rounded-md border border-border bg-muted/30 p-4">
              <div className="flex items-center gap-3">
                <span className="flex h-10 w-10 items-center justify-center rounded-md bg-primary/10 text-primary">
                  <group.icon className="h-5 w-5" />
                </span>
                <h3 className="text-sm font-semibold">{t(group.titleKey)}</h3>
              </div>
              <div className="mt-4 space-y-2">
                {group.items.map((item) => (
                  <div key={item.labelKey} className="flex items-start justify-between gap-3 text-sm">
                    <span className="min-w-0 break-words text-muted-foreground">{t(item.labelKey)}</span>
                    <StateBadge state={item.state} compact />
                  </div>
                ))}
              </div>
            </div>
          ))}
        </div>
      </CardContent>
    </Card>
  );
}

function RetrievalSettingsPanel({
  config,
  models,
  onChange,
}: {
  config: RetrievalConfig;
  models: ModelDefinition[];
  onChange: (config: RetrievalConfig) => void;
}) {
  const { t } = useTranslation();
  const embeddingOptions = buildModelOptions(models, t("knowledge.autoSelect"), "embedding", t);
  const rerankOptions = buildModelOptions(models, t("knowledge.autoSelect"), "rerank", t);

  function update(patch: Partial<RetrievalConfig>) {
    onChange({ ...config, ...patch });
  }

  return (
    <Card>
      <CardHeader>
        <CardTitle>{t("knowledge.retrievalSettings")}</CardTitle>
        <p className="text-sm text-muted-foreground">{t("knowledge.tuneRetrievalBehavior")}</p>
      </CardHeader>
      <CardContent className="space-y-5">
        <div className="rounded-md border border-border bg-muted/30 p-4">
          <div className="flex items-center gap-2">
            <Settings2 className="h-4 w-4 text-primary" />
            <p className="text-sm font-semibold">{t("knowledge.modelSelection")}</p>
          </div>
          <div className="mt-4 grid gap-3 lg:grid-cols-3">
            <Field label={t("knowledge.retrievalMode")}>
              <Select value={config.retrievalMode} onChange={(event) => update({ retrievalMode: event.target.value })} options={[
                { value: "hybrid", label: t("knowledge.hybridRetrieval") },
                { value: "vector", label: t("knowledge.vectorOnly") },
                { value: "keyword", label: t("knowledge.keywordOnly") },
              ]} />
            </Field>
            <Field label={t("knowledge.embeddingModel")}>
              <Select value={normalizeSelectedModel(config.embeddingModelId, embeddingOptions)} onChange={(event) => update({ embeddingModelId: event.target.value })} options={embeddingOptions} />
            </Field>
            <Field label={t("knowledge.rerankModel")}>
              <Select value={normalizeSelectedModel(config.rerankModelId, rerankOptions)} onChange={(event) => update({ rerankModelId: event.target.value })} options={rerankOptions} />
            </Field>
          </div>
          {!models.length ? (
            <p className="mt-3 rounded-md border border-amber-500/25 bg-amber-500/10 p-3 text-xs text-amber-700 dark:text-amber-200">
              {t("knowledge.noConfiguredModels")}
            </p>
          ) : null}
        </div>
        <div className="rounded-md border border-border bg-muted/30 p-4">
          <div className="flex items-center gap-2">
            <FileSearch className="h-4 w-4 text-primary" />
            <p className="text-sm font-semibold">{t("knowledge.retrievalDefaults")}</p>
          </div>
          <div className="mt-4 grid gap-3 md:grid-cols-2 2xl:grid-cols-5">
            <Field label={t("knowledge.chunkSize")}><Input inputMode="numeric" value={config.chunkSize} onChange={(event) => update({ chunkSize: event.target.value })} /></Field>
            <Field label={t("knowledge.chunkOverlap")}><Input inputMode="numeric" value={config.chunkOverlap} onChange={(event) => update({ chunkOverlap: event.target.value })} /></Field>
            <Field label={t("knowledge.topK")}><Input inputMode="numeric" value={config.topK} onChange={(event) => update({ topK: event.target.value })} /></Field>
            <Field label={t("knowledge.candidatePool")}><Input inputMode="numeric" value={config.maxCandidates} onChange={(event) => update({ maxCandidates: event.target.value })} /></Field>
            <Field label={t("knowledge.minimumScore")}><Input inputMode="decimal" value={config.minScore} onChange={(event) => update({ minScore: event.target.value })} /></Field>
          </div>
        </div>
        <div className="grid gap-3 lg:grid-cols-3">
          <Field label={t("knowledge.keywordWeight")}><Input value={config.keywordWeight} onChange={(event) => update({ keywordWeight: event.target.value })} /></Field>
          <Field label={t("knowledge.vectorWeight")}><Input value={config.vectorWeight} onChange={(event) => update({ vectorWeight: event.target.value })} /></Field>
          <Field label={t("knowledge.rerankWeight")}><Input value={config.rerankWeight} onChange={(event) => update({ rerankWeight: event.target.value })} /></Field>
        </div>
        <div className="grid gap-3">
          <ToggleRow icon={SlidersHorizontal} title={t("knowledge.queryRewrite")} description={t("knowledge.expandShortQueries")} checked={config.queryRewrite} onChange={(checked) => update({ queryRewrite: checked })} />
          <ToggleRow icon={FileSearch} title={t("knowledge.requireCitations")} description={t("knowledge.treatUncitedAnswers")} checked={config.requireCitations} onChange={(checked) => update({ requireCitations: checked })} />
        </div>
      </CardContent>
    </Card>
  );
}

function buildModelOptions(models: ModelDefinition[], autoLabel: string, capability: "embedding" | "rerank" | undefined, t: ReturnType<typeof useTranslation>["t"]) {
  const matchedModels = capability ? models.filter((model) => modelMatchesCapability(model, capability)) : models;
  const usableModels = matchedModels.length ? matchedModels : models;
  return [
    { value: "auto", label: autoLabel },
    ...usableModels.map((model) => ({
      value: model.id,
      label: `${demoText(model.name, t)} (${model.model_name})`,
    })),
  ];
}

function modelMatchesCapability(model: ModelDefinition, capability: "embedding" | "rerank") {
  const text = `${model.name} ${model.model_name} ${model.description ?? ""} ${model.capabilities_json.join(" ")}`.toLowerCase();
  if (capability === "embedding") {
    return text.includes("embed") || text.includes("vector");
  }
  return text.includes("rerank") || text.includes("ranker") || text.includes("re-rank");
}

function normalizeSelectedModel(value: string, options: Array<{ value: string; label: string }>) {
  return options.some((option) => option.value === value) ? value : "auto";
}

function settingsPayloadToForm(payload: KnowledgeSettingsPayload): RetrievalConfig {
  return {
    retrievalMode: payload.retrievalMode,
    embeddingModelId: payload.embeddingModelId,
    rerankModelId: payload.rerankModelId,
    chunkSize: String(payload.chunkSize),
    chunkOverlap: String(payload.chunkOverlap),
    topK: String(payload.topK),
    minScore: String(payload.minScore),
    maxCandidates: String(payload.maxCandidates),
    keywordWeight: String(payload.keywordWeight),
    vectorWeight: String(payload.vectorWeight),
    rerankWeight: String(payload.rerankWeight),
    queryRewrite: payload.queryRewrite,
    requireCitations: payload.requireCitations,
  };
}

function formToSettingsPayload(config: RetrievalConfig, knowledgeBaseId: string): KnowledgeSettingsPayload {
  return {
    knowledgeBaseId,
    retrievalMode: config.retrievalMode,
    embeddingModelId: config.embeddingModelId,
    rerankModelId: config.rerankModelId,
    chunkSize: readInteger(config.chunkSize, 800),
    chunkOverlap: readInteger(config.chunkOverlap, 120),
    topK: readInteger(config.topK, 5),
    minScore: readNumber(config.minScore, 0),
    maxCandidates: readInteger(config.maxCandidates, 50),
    keywordWeight: readNumber(config.keywordWeight, 0.55),
    vectorWeight: readNumber(config.vectorWeight, 0.3),
    rerankWeight: readNumber(config.rerankWeight, 0.15),
    queryRewrite: config.queryRewrite,
    requireCitations: config.requireCitations,
  };
}

function readInteger(value: string, fallback: number) {
  const parsed = Number(value);
  return Number.isFinite(parsed) ? Math.max(0, Math.round(parsed)) : fallback;
}

function readNumber(value: string, fallback: number) {
  const parsed = Number(value);
  return Number.isFinite(parsed) ? parsed : fallback;
}

function StateBadge({ state, compact }: { state: string; compact?: boolean }) {
  const { t } = useTranslation();
  const styles = {
    live: "border-green-500/30 bg-green-500/10 text-green-700 dark:text-green-200",
    mock: "border-blue-500/30 bg-blue-500/10 text-blue-700 dark:text-blue-200",
    prototype: "border-blue-500/30 bg-blue-500/10 text-blue-700 dark:text-blue-200",
  } as const;
  const labels: Record<string, string> = {
    live: t("knowledge.state.live"),
    mock: compact ? t("knowledge.state.mock") : t("knowledge.state.mock"),
    prototype: compact ? t("knowledge.state.proto") : t("knowledge.state.prototype"),
  };
  const key = state as keyof typeof styles;
  return <Badge className={`${styles[key] ?? styles.prototype} shrink-0 whitespace-nowrap`}>{labels[state] ?? state}</Badge>;
}

function SearchResultCard({ result }: { result: SearchResult }) {
  const { t } = useTranslation();

  return (
    <div className="rounded-md border border-border bg-muted/30 p-3">
      <div className="flex items-start justify-between gap-3">
        <div className="min-w-0">
          <p className="truncate text-sm font-semibold">{demoText(result.document.title, t)}</p>
          <p className="mt-1 text-xs text-muted-foreground">{t("knowledge.chunk")} {result.chunk.chunkIndex} / {result.chunk.tokenCount} {t("knowledge.tokens")}</p>
        </div>
        <span className="shrink-0 rounded-md bg-primary/10 px-2 py-1 font-mono text-xs text-primary">{result.score.toFixed(3)}</span>
      </div>
      <p className="mt-3 break-words text-sm leading-6 text-muted-foreground">{result.chunk.contentText}</p>
      <ScoreBreakdown score={result.score} details={result.scoreDetails} />
    </div>
  );
}

function ScoreBreakdown({ score, details }: { score: number; details?: JSONObject }) {
  const { t } = useTranslation();
  const entries = getReadableEntries(details).slice(0, 4);
  return (
    <div className="mt-3 rounded-md border border-border bg-surface-elevated p-3">
      <div className="flex items-center justify-between gap-3">
        <p className="text-xs font-medium text-muted-foreground">{t("knowledge.scoreDetails")}</p>
        <span className="shrink-0 rounded-sm bg-primary/10 px-2 py-1 font-mono text-xs text-primary">{Math.round(score * 100)}%</span>
      </div>
      {entries.length ? (
        <div className="mt-3 grid gap-2 sm:grid-cols-2">
          {entries.map(([key, value]) => (
            <Detail key={key} label={formatPropertyLabel(key, t)} value={formatPropertyValue(value, t)} />
          ))}
        </div>
      ) : (
        <p className="mt-2 text-xs text-muted-foreground">{t("knowledge.noExtraScoringSignals")}</p>
      )}
    </div>
  );
}

function MetadataSummary({ metadata }: { metadata?: JSONObject | null }) {
  const { t } = useTranslation();
  const entries = getReadableEntries(metadata);
  if (!entries.length) {
    return <EmptyState icon={FileSearch} title={t("knowledge.noProperties")} description={t("knowledge.noPropertiesDescription")} />;
  }
  return (
    <div className="grid gap-3 sm:grid-cols-2">
      {entries.map(([key, value]) => (
        <div key={key} className="rounded-md border border-border bg-muted/30 p-3">
          <p className="text-xs text-muted-foreground">{formatPropertyLabel(key, t)}</p>
          <p className="mt-1 break-words text-sm text-foreground">{formatPropertyValue(value, t)}</p>
        </div>
      ))}
    </div>
  );
}

function CreateKnowledgeBaseDialog({ open, onOpenChange, onCreated }: { open: boolean; onOpenChange: (open: boolean) => void; onCreated: () => void }) {
  const { t } = useTranslation();
  const [form, setForm] = React.useState({ name: "", description: "" });
  const [error, setError] = React.useState<string>();
  const [submitting, setSubmitting] = React.useState(false);

  async function submit(event: React.FormEvent) {
    event.preventDefault();
    setError(undefined);
    setSubmitting(true);
    try {
      await createKnowledgeBase({ name: form.name.trim(), description: form.description.trim() || null, metadata: {} });
      toast.success(t("knowledge.knowledgeBaseCreated"));
      onOpenChange(false);
      setForm({ name: "", description: "" });
      onCreated();
    } finally {
      setSubmitting(false);
    }
  }

  return (
    <Dialog open={open} onOpenChange={onOpenChange} title={t("knowledge.createKnowledgeBase")} className="max-w-2xl">
      <form className="space-y-4" onSubmit={submit}>
        {error ? <p className="rounded-md border border-red-500/25 bg-red-500/10 p-3 text-sm text-red-700 dark:text-red-200">{error}</p> : null}
        <Field label={t("common.name")}><Input required value={form.name} onChange={(event) => setForm({ ...form, name: event.target.value })} /></Field>
        <Field label={t("common.description")}><Textarea value={form.description} onChange={(event) => setForm({ ...form, description: event.target.value })} /></Field>
        <div className="flex justify-end gap-2">
          <Button type="button" variant="ghost" onClick={() => onOpenChange(false)}>{t("common.cancel")}</Button>
          <Button disabled={submitting}>{submitting ? t("common.creating") : t("common.create")}</Button>
        </div>
      </form>
    </Dialog>
  );
}

function CreateKnowledgeDocumentDialog({
  open,
  onOpenChange,
  knowledgeBaseId,
  knowledgeBaseName,
  onCreated,
}: {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  knowledgeBaseId?: string;
  knowledgeBaseName?: string;
  onCreated: (ingest: KnowledgeDocumentIngestResponse) => void;
}) {
  const { t } = useTranslation();
  const [form, setForm] = React.useState({
    title: "",
    sourceType: "text",
    sourceUri: "",
    contentText: "",
    chunkSize: "800",
    chunkOverlap: "120",
  });
  const [parsePreview, setParsePreview] = React.useState<KnowledgeDocumentParseResponse>();
  const [error, setError] = React.useState<string>();
  const [parsing, setParsing] = React.useState(false);
  const [submitting, setSubmitting] = React.useState(false);

  async function previewParse() {
    setError(undefined);
    setParsing(true);
    try {
      const parsed = await parseKnowledgeDocument({
        sourceType: form.sourceType,
        sourceUri: form.sourceUri.trim() || null,
        contentText: form.contentText,
      });
      setParsePreview(parsed);
      toast.success(t("knowledge.parsePreviewReady"));
    } catch (err) {
      setError(translateApiError(err));
    } finally {
      setParsing(false);
    }
  }

  async function submit(event: React.FormEvent) {
    event.preventDefault();
    if (!knowledgeBaseId) return;
    setError(undefined);
    setSubmitting(true);
    try {
      const ingest = await createKnowledgeDocument({
        knowledgeBaseId,
        title: form.title.trim(),
        sourceType: form.sourceType,
        sourceUri: form.sourceUri.trim() || null,
        contentText: form.contentText,
        chunkSize: Number(form.chunkSize) || null,
        chunkOverlap: Number(form.chunkOverlap) || null,
        metadata: {},
      });
      toast.success(ingest.queued ? t("knowledge.documentQueued") : t("knowledge.documentIndexedWithChunks", { count: ingest.chunks.length }));
      onOpenChange(false);
      setForm({ title: "", sourceType: "text", sourceUri: "", contentText: "", chunkSize: "800", chunkOverlap: "120" });
      setParsePreview(undefined);
      onCreated(ingest);
    } catch (err) {
      setError(translateApiError(err));
    } finally {
      setSubmitting(false);
    }
  }

  return (
    <Dialog open={open} onOpenChange={onOpenChange} title={t("knowledge.addDocument")} className="max-w-4xl">
      <form className="space-y-4" onSubmit={submit}>
        {error ? <p className="rounded-md border border-red-500/25 bg-red-500/10 p-3 text-sm text-red-700 dark:text-red-200">{error}</p> : null}
        <div className="rounded-md border border-primary/20 bg-primary/10 p-3">
          <p className="text-sm font-medium">{t("knowledge.targetBase")}: {knowledgeBaseName ?? t("knowledge.noBaseSelected")}</p>
          <p className="mt-1 text-xs leading-5 text-muted-foreground">
            {t("knowledge.documentTargetHint")}
          </p>
        </div>
        <div className="grid gap-3 lg:grid-cols-2">
          <Field label={t("knowledge.addDocumentTitle")}><Input required value={form.title} onChange={(event) => setForm({ ...form, title: event.target.value })} /></Field>
          <Field label={t("knowledge.sourceType")}>
            <Select value={form.sourceType} onChange={(event) => setForm({ ...form, sourceType: event.target.value })} options={sourceTypeValues.filter((value) => value !== "all").map((value) => ({ value, label: t(`knowledge.sourceLabels.${value}`) }))} />
          </Field>
        </div>
        <Field label={t("knowledge.sourceUri")}><Input value={form.sourceUri} onChange={(event) => setForm({ ...form, sourceUri: event.target.value })} placeholder="https://docs.example.com/page" /></Field>
        <Field label={t("knowledge.content")}><Textarea required className="min-h-40" value={form.contentText} onChange={(event) => setForm({ ...form, contentText: event.target.value })} /></Field>
        <div className="grid gap-3 lg:grid-cols-2">
          <Field label={t("knowledge.chunkSize")}><Input inputMode="numeric" value={form.chunkSize} onChange={(event) => setForm({ ...form, chunkSize: event.target.value })} /></Field>
          <Field label={t("knowledge.chunkOverlap")}><Input inputMode="numeric" value={form.chunkOverlap} onChange={(event) => setForm({ ...form, chunkOverlap: event.target.value })} /></Field>
        </div>
        {parsePreview ? (
          <div className="rounded-md border border-border bg-muted/30 p-3">
            <p className="text-sm font-medium">{t("knowledge.parsePreview")}</p>
            <p className="mt-1 line-clamp-3 text-sm text-muted-foreground">{parsePreview.contentText}</p>
            <MetadataSummary metadata={parsePreview.metadata} />
          </div>
        ) : null}
        <div className="flex flex-wrap justify-end gap-2">
          <Button type="button" variant="ghost" onClick={() => onOpenChange(false)}>{t("common.cancel")}</Button>
          <Button type="button" variant="secondary" disabled={parsing || !form.contentText.trim()} onClick={() => void previewParse()}>
            {parsing ? t("knowledge.parsing") : t("knowledge.previewParse")}
          </Button>
          <Button disabled={submitting || !knowledgeBaseId}>{submitting ? t("knowledge.indexing") : t("knowledge.indexDocument")}</Button>
        </div>
      </form>
    </Dialog>
  );
}

function Detail({ label, value }: { label: string; value: string }) {
  return (
    <div className="min-w-0">
      <p className="text-xs text-muted-foreground">{label}</p>
      <p className="mt-1 break-words font-mono text-xs text-foreground">{value}</p>
    </div>
  );
}

function Field({ label, children }: { label: string; children: React.ReactNode }) {
  return <label className="block space-y-2 text-sm"><span className="text-muted-foreground">{label}</span>{children}</label>;
}

function formatKnowledgeJobType(value: string, t: ReturnType<typeof useTranslation>["t"]) {
  const known: Record<string, string> = {
    "Sitemap Sync": "sitemapSync",
    "Re-index": "reindex",
    "PDF Batch": "pdfBatch",
    index: "index",
    reindex: "reindex",
  };
  const key = known[value];
  return key ? t(`knowledge.jobTypes.${key}`) : value;
}

function toKnowledgeJob(job: KnowledgeIndexJob): KnowledgeJob {
  return {
    id: job.jobId,
    type: job.action,
    target: job.documentTitle || job.documentId,
    status: job.status,
    progress: job.progress,
    createdTime: job.queuedTime || job.startedTime || job.completedTime || new Date().toISOString(),
    workerKey: job.workerKey,
    errorMessage: job.errorMessage,
  };
}

function formatKnowledgeJobTarget(value: string, t: ReturnType<typeof useTranslation>["t"]) {
  const known: Record<string, string> = {
    "Product Docs": "productDocs",
    "Policy Pack": "policyPack",
  };
  const key = known[value];
  return key ? t(`knowledge.jobTargets.${key}`) : value;
}

function formatEvalText(value: string, t: ReturnType<typeof useTranslation>["t"]) {
  const known: Record<string, string> = {
    "Where can customers download invoices?": "downloadInvoices",
    "Billing and Invoice FAQ": "billingInvoiceFaq",
    "How do refunds affect annual plans?": "annualPlanRefunds",
    "Refund policy": "refundPolicy",
  };
  const key = known[value];
  return key ? t(`knowledge.evalSamples.${key}`) : value;
}

function humanizeCode(value: string) {
  return value
    .replace(/_/g, " ")
    .replace(/\b\w/g, (letter) => letter.toUpperCase());
}

function getReadableEntries(metadata?: JSONObject | null): Array<[string, unknown]> {
  return Object.entries(metadata ?? {}).filter(([, value]) => value !== undefined && value !== null && value !== "");
}

function formatPropertyLabel(value: string, t?: ReturnType<typeof useTranslation>["t"]) {
  const normalized = value.replace(/_json$/i, "");
  const fallback = normalized
    .replace(/_json$/i, "")
    .replace(/_/g, " ")
    .replace(/\b\w/g, (letter) => letter.toUpperCase());
  return t ? t(`knowledge.propertyLabels.${normalized}`, fallback) : fallback;
}

function formatPropertyValue(value: unknown, t?: ReturnType<typeof useTranslation>["t"]): string {
  if (Array.isArray(value)) {
    return value.map((item) => formatPropertyValue(item, t)).join(", ");
  }
  if (typeof value === "object" && value !== null) {
    const summary = Object.entries(value)
      .slice(0, 3)
      .map(([key, item]) => `${formatPropertyLabel(key, t)}: ${formatPropertyValue(item, t)}`)
      .join("; ");
    return summary || (t ? t("common.configured") : "Configured");
  }
  if (typeof value === "boolean") {
    return value ? (t ? t("common.yes") : "Yes") : (t ? t("common.no") : "No");
  }
  return String(value);
}
