"use client";

import { useState, useCallback, useMemo } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import {
  ChevronDown,
  ChevronRight,
  Save,
  Languages,
  Loader2,
  Search,
  AlertTriangle,
  History,
  X,
  Download,
  Upload,
} from "lucide-react";
import { toast } from "sonner";
import { cn } from "@/lib/utils/cn";
import { useTranslation } from "@/lib/hooks/use-translation";
import { adminApi, aiApi } from "@/lib/api/client";

/* ─── Types ─── */

interface CmsField {
  id: number;
  section: string;
  groupKey: string;
  fieldKey: string;
  titleHi: string;
  titleEn: string;
  valueHi: string;
  valueEn: string;
  fieldType: string;
  sortOrder: number;
}

interface CmsHistoryEntry {
  id: number;
  cmsId: number;
  valueHi: string;
  valueEn: string;
  changedByName: string;
  changedAt: string;
}

/* ─── Page display names ───
   Two lists, and both had stopped at the sections V2 created: the seventeen
   that arrived later with the legacy pages (V15/V16) and the UPI details had
   neither a name nor a place, so they fell to the bottom of the screen showing
   their raw enum — PAYMENT among them, which is where the editor is meant to
   put the journal's UPI id. Labels are the ones the public navigation already
   uses, so a row here reads the same as the page it edits. */

const PAGE_DISPLAY: Record<string, { hi: string; en: string }> = {
  LANDING: { hi: "लैंडिंग पेज", en: "Landing Page" },
  NAVBAR: { hi: "नेविगेशन बार", en: "Navigation Bar" },
  FOOTER: { hi: "फ़ुटर", en: "Footer" },
  LOGIN: { hi: "लॉगिन / पंजीकरण", en: "Login / Register" },
  SUBMIT: { hi: "शोधपत्र जमा", en: "Submit Paper" },
  AUTHOR: { hi: "लेखक डैशबोर्ड", en: "Author Dashboard" },
  REVIEWER: { hi: "समीक्षक डैशबोर्ड", en: "Reviewer Dashboard" },
  ADMIN: { hi: "प्रशासन डैशबोर्ड", en: "Admin Dashboard" },
  ADMIN_PAPERS: { hi: "शोधपत्र प्रबंधन", en: "Paper Management" },
  ADMIN_USERS: { hi: "उपयोगकर्ता प्रबंधन", en: "User Management" },
  ADMIN_CATEGORIES: { hi: "श्रेणी प्रबंधन", en: "Category Management" },
  SIDEBAR: { hi: "साइडबार", en: "Sidebar" },
  COMMON: { hi: "सामान्य", en: "Common" },
  STATUS_LABELS: { hi: "स्थिति लेबल", en: "Status Labels" },
  TOAST: { hi: "सूचनाएँ", en: "Notifications (Toast)" },
  VALIDATION: { hi: "सत्यापन संदेश", en: "Validation Messages" },
  ABOUT: { hi: "हमारे बारे में", en: "About" },
  CONTACT: { hi: "संपर्क", en: "Contact" },
  PRIVACY: { hi: "गोपनीयता", en: "Privacy Policy" },
  ERROR: { hi: "त्रुटि पृष्ठ", en: "Error Pages" },
  MAGAZINE: { hi: "पत्रिका", en: "Magazine" },
  JOURNALS: { hi: "जर्नल", en: "Journals" },

  // The Journal desk
  JOURNAL_ABOUT: { hi: "पत्रिका के बारे में", en: "About the Journal" },
  JOURNAL_AIMS: { hi: "लक्ष्य एवं उद्देश्य", en: "Aims & Objectives" },
  JOURNAL_IMPACT_FACTOR: { hi: "प्रभाव कारक", en: "Impact Factor" },
  JOURNAL_EDITORIAL_BOARD: { hi: "संपादकीय बोर्ड", en: "Editorial Board" },
  JOURNAL_SPECIAL_ISSUE: { hi: "विशेष अंक", en: "Special Issue" },

  // The Author's desk
  AUTHOR_GUIDELINES: { hi: "प्रस्तुति दिशानिर्देश", en: "Submission Guidelines" },
  AUTHOR_SUBSCRIPTION: { hi: "सदस्यता शुल्क", en: "Subscription Fee" },
  AUTHOR_PUBLICATION_FEE: { hi: "प्रकाशन शुल्क", en: "Publication Fee" },
  AUTHOR_DEADLINES: { hi: "समय-सीमाएँ", en: "Submission Deadlines" },
  AUTHOR_PEER_REVIEW: { hi: "समीक्षा प्रक्रिया", en: "Peer Review Process" },
  AUTHOR_CALL_FOR_PAPERS: { hi: "शोधपत्र आमंत्रण", en: "Call for Papers" },

  // The Information desk
  INFO_DOCTORAL_COLLOQUIUM: { hi: "डॉक्टरल संगोष्ठी", en: "Doctoral Colloquium" },
  INFO_WORKSHOPS: { hi: "शैक्षणिक कार्यशाला", en: "Academic Workshops" },
  INFO_TRAINING: { hi: "शैक्षणिक प्रशिक्षण", en: "Academic Training" },
  INFO_GRANT_INSTITUTIONS: { hi: "शोध अनुदानदाता संस्थाएँ", en: "Grant Institutions" },

  DISCLAIMER: { hi: "अस्वीकरण", en: "Disclaimer" },
  // Not a public page: the UPI id and payee name an author is asked to pay.
  PAYMENT: { hi: "भुगतान विवरण (UPI)", en: "Payment Details (UPI)" },
};

// Grouped as the public site groups them, so an editor looking for a page
// finds it under the desk it appears on.
const SECTION_ORDER = [
  "LANDING", "NAVBAR", "FOOTER", "SIDEBAR",
  "LOGIN", "SUBMIT", "AUTHOR", "REVIEWER",
  "ADMIN", "ADMIN_PAPERS", "ADMIN_USERS", "ADMIN_CATEGORIES",
  "COMMON", "STATUS_LABELS", "TOAST", "VALIDATION",

  "JOURNAL_ABOUT", "JOURNAL_AIMS", "JOURNAL_IMPACT_FACTOR",
  "JOURNAL_EDITORIAL_BOARD", "JOURNAL_SPECIAL_ISSUE",

  "AUTHOR_GUIDELINES", "AUTHOR_SUBSCRIPTION", "AUTHOR_PUBLICATION_FEE",
  "AUTHOR_DEADLINES", "AUTHOR_PEER_REVIEW", "AUTHOR_CALL_FOR_PAPERS",

  "INFO_DOCTORAL_COLLOQUIUM", "INFO_WORKSHOPS", "INFO_TRAINING",
  "INFO_GRANT_INSTITUTIONS",

  "PAYMENT",
  "ABOUT", "CONTACT", "PRIVACY", "DISCLAIMER", "ERROR",
  "MAGAZINE", "JOURNALS",
];

/* ─── Component ─── */

export default function PageContentAdmin() {
  const queryClient = useQueryClient();
  const { t: cms } = useTranslation("COMMON");
  const [viewLang, setViewLang] = useState<"hi" | "en">("hi");
  const [expandedPages, setExpandedPages] = useState<Set<string>>(new Set());
  const [dirty, setDirty] = useState<Map<number, { valueHi: string; valueEn: string }>>(new Map());
  const [translating, setTranslating] = useState<number | null>(null);
  const [searchQuery, setSearchQuery] = useState("");
  const [showEmptyOnly, setShowEmptyOnly] = useState(false);
  const [historyFieldId, setHistoryFieldId] = useState<number | null>(null);

  // Fetch all CMS content
  const { data: allFields, isLoading } = useQuery<CmsField[]>({
    queryKey: ["admin-cms-all"],
    queryFn: async () => {
      const res = await adminApi.cmsAll();
      return res.data ?? [];
    },
  });

  // Fetch history for a specific field
  const { data: historyData, isLoading: historyLoading } = useQuery<CmsHistoryEntry[]>({
    queryKey: ["cms-history", historyFieldId],
    queryFn: async () => {
      if (!historyFieldId) return [];
      const res = await adminApi.cmsHistory(historyFieldId);
      return res.data ?? [];
    },
    enabled: historyFieldId !== null,
  });

  // Gap #3: Search/filter — filter fields by search query
  const filteredFields = useMemo(() => {
    if (!allFields) return [];
    let fields = allFields;

    if (searchQuery.trim()) {
      const q = searchQuery.toLowerCase();
      fields = fields.filter(
        (f) =>
          f.fieldKey.toLowerCase().includes(q) ||
          f.groupKey.toLowerCase().includes(q) ||
          f.section.toLowerCase().includes(q) ||
          f.valueHi.toLowerCase().includes(q) ||
          f.valueEn.toLowerCase().includes(q) ||
          f.titleHi.toLowerCase().includes(q) ||
          f.titleEn.toLowerCase().includes(q)
      );
    }

    // Gap #4: Empty value filter
    if (showEmptyOnly) {
      fields = fields.filter((f) => {
        const dVal = dirty.get(f.id);
        const hi = dVal ? dVal.valueHi : f.valueHi;
        const en = dVal ? dVal.valueEn : f.valueEn;
        return !hi.trim() || !en.trim();
      });
    }

    return fields;
  }, [allFields, searchQuery, showEmptyOnly, dirty]);

  // Group filtered fields by section → groupKey
  const groupedData = useMemo(() => {
    const map = new Map<string, Map<string, CmsField[]>>();
    for (const field of filteredFields) {
      if (!map.has(field.section)) map.set(field.section, new Map());
      const sectionMap = map.get(field.section)!;
      if (!sectionMap.has(field.groupKey)) sectionMap.set(field.groupKey, []);
      sectionMap.get(field.groupKey)!.push(field);
    }
    return map;
  }, [filteredFields]);

  // Count empty fields for the warning badge
  const emptyFieldCount = useMemo(() => {
    if (!allFields) return 0;
    return allFields.filter((f) => {
      const dVal = dirty.get(f.id);
      const hi = dVal ? dVal.valueHi : f.valueHi;
      const en = dVal ? dVal.valueEn : f.valueEn;
      return !hi.trim() || !en.trim();
    }).length;
  }, [allFields, dirty]);

  // Save mutation
  const saveMutation = useMutation({
    mutationFn: async (items: { id: number; valueHi: string; valueEn: string }[]) => {
      await adminApi.batchUpdateCms(items);
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["admin-cms-all"] });
      queryClient.invalidateQueries({ queryKey: ["cms-content"] });
      queryClient.invalidateQueries({ queryKey: ["cms-bulk"] });
      setDirty(new Map());
      toast.success(viewLang === "hi" ? "सहेजा गया" : "Saved successfully");
    },
    onError: () => {
      toast.error(viewLang === "hi" ? "सहेजने में त्रुटि" : "Failed to save");
    },
  });

  // The translate button reaches the same AI provider as the submit form, so it
  // has to be gated the same way — otherwise it stays enabled on an instance
  // with no key and fails only on click.
  const { data: aiStatus } = useQuery({
    queryKey: ["ai-status"],
    queryFn: async () => (await aiApi.status()).data,
    staleTime: Infinity,
    retry: false,
  });
  const aiAvailable = aiStatus?.configured === true;

  // Translate mutation
  async function handleTranslate(field: CmsField) {
    if (!aiAvailable) return;
    setTranslating(field.id);
    try {
      const res = await adminApi.translateCmsField(field.id, viewLang);
      const translated = res.data?.translatedText ?? "";
      // An empty result must not overwrite existing content with nothing.
      if (!translated.trim()) {
        toast.error(viewLang === "hi" ? "अनुवाद खाली आया" : "Translation came back empty");
        setTranslating(null);
        return;
      }
      const targetLang = viewLang === "hi" ? "en" : "hi";
      const current = dirty.get(field.id) ?? { valueHi: field.valueHi, valueEn: field.valueEn };
      const updated = {
        ...current,
        [targetLang === "hi" ? "valueHi" : "valueEn"]: translated,
      };
      setDirty(new Map(dirty).set(field.id, updated));
      toast.success(viewLang === "hi" ? "अनुवाद हो गया" : "Translated");
    } catch (err: unknown) {
      const status = (err as { response?: { status?: number } })?.response?.status;
      toast.error(
        status === 429
          ? viewLang === "hi"
            ? "बहुत अधिक AI अनुरोध — कुछ समय बाद प्रयास करें"
            : "Too many AI requests — please try again shortly"
          : status === 503
            ? viewLang === "hi"
              ? "एआई सेवा उपलब्ध नहीं है"
              : "AI service is unavailable"
            : viewLang === "hi"
              ? "अनुवाद विफल"
              : "Translation failed"
      );
    }
    setTranslating(null);
  }

  function handleFieldChange(field: CmsField, lang: "hi" | "en", value: string) {
    const current = dirty.get(field.id) ?? { valueHi: field.valueHi, valueEn: field.valueEn };
    const updated = {
      ...current,
      [lang === "hi" ? "valueHi" : "valueEn"]: value,
    };
    setDirty(new Map(dirty).set(field.id, updated));
  }

  function getFieldValue(field: CmsField, lang: "hi" | "en"): string {
    const d = dirty.get(field.id);
    if (d) return lang === "hi" ? d.valueHi : d.valueEn;
    return lang === "hi" ? field.valueHi : field.valueEn;
  }

  function handleSaveAll() {
    if (dirty.size === 0) return;
    const items = Array.from(dirty.entries()).map(([id, vals]) => ({
      id,
      valueHi: vals.valueHi,
      valueEn: vals.valueEn,
    }));
    saveMutation.mutate(items);
  }

  function handleSaveSection(sectionFields: CmsField[]) {
    const items: { id: number; valueHi: string; valueEn: string }[] = [];
    for (const f of sectionFields) {
      const d = dirty.get(f.id);
      if (d) items.push({ id: f.id, valueHi: d.valueHi, valueEn: d.valueEn });
    }
    if (items.length === 0) {
      toast.info(viewLang === "hi" ? "कोई बदलाव नहीं" : "No changes");
      return;
    }
    saveMutation.mutate(items);
  }

  function togglePage(page: string) {
    const next = new Set(expandedPages);
    if (next.has(page)) next.delete(page);
    else next.add(page);
    setExpandedPages(next);
  }

  // Export/Import handlers
  async function handleExport() {
    try {
      const res = await adminApi.cmsExport();
      const blob = new Blob([JSON.stringify(res.data, null, 2)], { type: "application/json" });
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = `cms-export-${new Date().toISOString().slice(0, 10)}.json`;
      a.click();
      URL.revokeObjectURL(url);
      toast.success(viewLang === "hi" ? "निर्यात सफल" : "Export successful");
    } catch {
      toast.error(viewLang === "hi" ? "निर्यात विफल" : "Export failed");
    }
  }

  function handleImport() {
    const input = document.createElement("input");
    input.type = "file";
    input.accept = ".json";
    input.onchange = async (e) => {
      const file = (e.target as HTMLInputElement).files?.[0];
      if (!file) return;
      try {
        const text = await file.text();
        const items = JSON.parse(text);
        await adminApi.cmsImport(items);
        queryClient.invalidateQueries({ queryKey: ["admin-cms-all"] });
        toast.success(viewLang === "hi" ? "आयात सफल" : "Import successful");
      } catch {
        toast.error(viewLang === "hi" ? "आयात विफल" : "Import failed");
      }
    };
    input.click();
  }

  if (isLoading) {
    return (
      <div className="flex flex-col items-center justify-center h-64 gap-3">
        <Loader2 className="h-8 w-8 animate-spin text-indigo-500" />
        <p className="text-gray-500 text-sm">{cms("labels.loading", "Loading...")}</p>
      </div>
    );
  }

  const sortedSections = SECTION_ORDER.filter((s) => groupedData.has(s));
  // Also include any sections not in SECTION_ORDER
  const extraSections = Array.from(groupedData.keys()).filter((s) => !SECTION_ORDER.includes(s));

  return (
    <div className="max-w-5xl mx-auto px-4 py-6">
      {/* Header */}
      <div className="flex flex-col gap-4 mb-6">
        <div className="flex items-center justify-between">
          <div>
            <h1 className="text-2xl font-bold text-gray-900">
              {viewLang === "hi" ? "पृष्ठ सामग्री प्रबंधन" : "Page Content Management"}
            </h1>
            <p className="text-sm text-gray-500 mt-1">
              {viewLang === "hi"
                ? "सभी पृष्ठों का टेक्स्ट यहाँ संपादित करें"
                : "Edit text content of all pages here"}
            </p>
          </div>
          <div className="flex items-center gap-2">
            {/* Export/Import */}
            <button
              onClick={handleExport}
              className="flex items-center gap-1.5 rounded-md border border-gray-300 px-3 py-1.5 text-xs font-medium text-gray-600 hover:bg-gray-50 transition"
              title="Export CMS"
            >
              <Download className="h-3.5 w-3.5" />
              {viewLang === "hi" ? "निर्यात" : "Export"}
            </button>
            <button
              onClick={handleImport}
              className="flex items-center gap-1.5 rounded-md border border-gray-300 px-3 py-1.5 text-xs font-medium text-gray-600 hover:bg-gray-50 transition"
              title="Import CMS"
            >
              <Upload className="h-3.5 w-3.5" />
              {viewLang === "hi" ? "आयात" : "Import"}
            </button>

            {/* Language toggle */}
            <div className="flex rounded-lg border border-gray-300 overflow-hidden">
              <button
                onClick={() => setViewLang("hi")}
                className={cn(
                  "px-3 py-1.5 text-sm font-medium transition",
                  viewLang === "hi"
                    ? "bg-indigo-600 text-white"
                    : "bg-white text-gray-600 hover:bg-gray-50"
                )}
              >
                हिन्दी
              </button>
              <button
                onClick={() => setViewLang("en")}
                className={cn(
                  "px-3 py-1.5 text-sm font-medium transition",
                  viewLang === "en"
                    ? "bg-indigo-600 text-white"
                    : "bg-white text-gray-600 hover:bg-gray-50"
                )}
              >
                English
              </button>
            </div>

            {/* Save All */}
            <button
              onClick={handleSaveAll}
              disabled={dirty.size === 0 || saveMutation.isPending}
              className={cn(
                "flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-semibold transition",
                dirty.size > 0
                  ? "bg-indigo-600 text-white hover:bg-indigo-700"
                  : "bg-gray-100 text-gray-400 cursor-not-allowed"
              )}
            >
              {saveMutation.isPending ? (
                <Loader2 className="h-4 w-4 animate-spin" />
              ) : (
                <Save className="h-4 w-4" />
              )}
              {viewLang === "hi" ? "सभी सहेजें" : "Save All"}
              {dirty.size > 0 && (
                <span className="ml-1 rounded-full bg-white/20 px-2 py-0.5 text-xs">
                  {dirty.size}
                </span>
              )}
            </button>
          </div>
        </div>

        {/* Gap #3: Search bar + Gap #4: Empty filter */}
        <div className="flex items-center gap-3">
          <div className="relative flex-1">
            <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" />
            <input
              type="text"
              value={searchQuery}
              onChange={(e) => setSearchQuery(e.target.value)}
              placeholder={viewLang === "hi" ? "कुंजी, मान, या शीर्षक खोजें..." : "Search by key, value, or title..."}
              className="w-full rounded-lg border border-gray-300 bg-white py-2 pl-9 pr-9 text-sm text-gray-700 placeholder-gray-400 focus:border-indigo-400 focus:outline-none focus:ring-1 focus:ring-indigo-400"
            />
            {searchQuery && (
              <button
                onClick={() => setSearchQuery("")}
                className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
              >
                <X className="h-4 w-4" />
              </button>
            )}
          </div>

          {/* Gap #4: Empty value warning toggle */}
          <button
            onClick={() => setShowEmptyOnly(!showEmptyOnly)}
            className={cn(
              "flex items-center gap-1.5 rounded-lg border px-3 py-2 text-sm font-medium transition whitespace-nowrap",
              showEmptyOnly
                ? "border-amber-300 bg-amber-50 text-amber-700"
                : "border-gray-300 bg-white text-gray-600 hover:bg-gray-50"
            )}
          >
            <AlertTriangle className="h-4 w-4" />
            {viewLang === "hi" ? "खाली मान" : "Empty values"}
            {emptyFieldCount > 0 && (
              <span className={cn(
                "rounded-full px-1.5 py-0.5 text-xs font-semibold",
                showEmptyOnly ? "bg-amber-200 text-amber-800" : "bg-red-100 text-red-700"
              )}>
                {emptyFieldCount}
              </span>
            )}
          </button>
        </div>

        {/* Search results count */}
        {(searchQuery || showEmptyOnly) && (
          <p className="text-xs text-gray-500">
            {filteredFields.length} {viewLang === "hi" ? "परिणाम मिले" : "results found"}
            {searchQuery && (
              <span className="ml-1">
                {viewLang === "hi" ? `"${searchQuery}" के लिए` : `for "${searchQuery}"`}
              </span>
            )}
          </p>
        )}
      </div>

      {/* Pages accordion */}
      <div className="space-y-2">
        {[...sortedSections, ...extraSections].map((section) => {
          const sectionGroups = groupedData.get(section)!;
          const isExpanded = expandedPages.has(section);
          const display = PAGE_DISPLAY[section] ?? { hi: section, en: section };
          const allSectionFields = Array.from(sectionGroups.values()).flat();
          const sectionDirtyCount = allSectionFields.filter((f) => dirty.has(f.id)).length;
          const sectionEmptyCount = allSectionFields.filter((f) => {
            const dVal = dirty.get(f.id);
            const hi = dVal ? dVal.valueHi : f.valueHi;
            const en = dVal ? dVal.valueEn : f.valueEn;
            return !hi.trim() || !en.trim();
          }).length;

          return (
            <div key={section} className="border border-gray-200 rounded-lg overflow-hidden">
              {/* Page header */}
              <button
                onClick={() => togglePage(section)}
                className="flex items-center justify-between w-full px-4 py-3 bg-gray-50 hover:bg-gray-100 transition"
              >
                <div className="flex items-center gap-3">
                  {isExpanded ? (
                    <ChevronDown className="h-4 w-4 text-gray-500" />
                  ) : (
                    <ChevronRight className="h-4 w-4 text-gray-500" />
                  )}
                  <span className="text-sm font-semibold text-gray-900">
                    {viewLang === "hi" ? display.hi : display.en}
                  </span>
                  <span className="text-xs text-gray-400">
                    {allSectionFields.length} {viewLang === "hi" ? "फ़ील्ड" : "fields"}
                  </span>
                </div>
                <div className="flex items-center gap-2">
                  {/* Gap #4: Empty count warning badge */}
                  {sectionEmptyCount > 0 && (
                    <span className="flex items-center gap-1 rounded-full bg-red-50 text-red-600 px-2 py-0.5 text-xs font-medium">
                      <AlertTriangle className="h-3 w-3" />
                      {sectionEmptyCount} {viewLang === "hi" ? "खाली" : "empty"}
                    </span>
                  )}
                  {sectionDirtyCount > 0 && (
                    <span className="rounded-full bg-amber-100 text-amber-700 px-2 py-0.5 text-xs font-medium">
                      {sectionDirtyCount} {viewLang === "hi" ? "बदलाव" : "changes"}
                    </span>
                  )}
                </div>
              </button>

              {/* Expanded content */}
              {isExpanded && (
                <div className="p-4 space-y-6">
                  {Array.from(sectionGroups.entries()).map(([groupKey, fields]) => (
                    <div key={groupKey}>
                      {/* Group header */}
                      <div className="flex items-center justify-between mb-3">
                        <h3 className="text-xs font-semibold text-indigo-600 uppercase tracking-wide">
                          {groupKey.replace(/_/g, " ")}
                        </h3>
                      </div>

                      {/* Fields */}
                      <div className="space-y-3">
                        {fields
                          .sort((a, b) => a.sortOrder - b.sortOrder)
                          .map((field) => {
                            const hiVal = getFieldValue(field, "hi");
                            const enVal = getFieldValue(field, "en");
                            const isEmpty = !hiVal.trim() || !enVal.trim();

                            return (
                              <FieldEditor
                                key={field.id}
                                field={field}
                                viewLang={viewLang}
                                value={getFieldValue(field, viewLang)}
                                otherLangValue={getFieldValue(
                                  field,
                                  viewLang === "hi" ? "en" : "hi"
                                )}
                                isDirty={dirty.has(field.id)}
                                isEmpty={isEmpty}
                                isTranslating={translating === field.id}
                                onChangeValue={(val) =>
                                  handleFieldChange(field, viewLang, val)
                                }
                                aiAvailable={aiAvailable}
                                onTranslate={() => handleTranslate(field)}
                                onShowHistory={() => setHistoryFieldId(field.id)}
                              />
                            );
                          })}
                      </div>
                    </div>
                  ))}

                  {/* Save section button */}
                  <div className="flex justify-end pt-2 border-t border-gray-100">
                    <button
                      onClick={() => handleSaveSection(allSectionFields)}
                      disabled={sectionDirtyCount === 0 || saveMutation.isPending}
                      className={cn(
                        "flex items-center gap-2 rounded-md px-3 py-1.5 text-sm font-medium transition",
                        sectionDirtyCount > 0
                          ? "bg-indigo-600 text-white hover:bg-indigo-700"
                          : "bg-gray-100 text-gray-400 cursor-not-allowed"
                      )}
                    >
                      <Save className="h-3.5 w-3.5" />
                      {viewLang === "hi" ? "इस अनुभाग को सहेजें" : "Save This Section"}
                    </button>
                  </div>
                </div>
              )}
            </div>
          );
        })}

        {/* No results */}
        {sortedSections.length === 0 && extraSections.length === 0 && (
          <div className="text-center py-12 text-gray-500">
            <Search className="mx-auto h-8 w-8 text-gray-300 mb-2" />
            <p>{viewLang === "hi" ? "कोई परिणाम नहीं मिला" : "No results found"}</p>
          </div>
        )}
      </div>

      {/* Gap #2: History Modal */}
      {historyFieldId !== null && (
        <HistoryModal
          fieldId={historyFieldId}
          entries={historyData ?? []}
          isLoading={historyLoading}
          viewLang={viewLang}
          onClose={() => setHistoryFieldId(null)}
        />
      )}
    </div>
  );
}

/* ─── Field Editor (enhanced with Gap #2 history + Gap #4 empty warning) ─── */

function FieldEditor({
  field,
  viewLang,
  value,
  otherLangValue,
  isDirty,
  isEmpty,
  isTranslating,
  aiAvailable,
  onChangeValue,
  onTranslate,
  onShowHistory,
}: {
  field: CmsField;
  viewLang: "hi" | "en";
  value: string;
  otherLangValue: string;
  isDirty: boolean;
  isEmpty: boolean;
  isTranslating: boolean;
  aiAvailable: boolean;
  onChangeValue: (val: string) => void;
  onTranslate: () => void;
  onShowHistory: () => void;
}) {
  const label = viewLang === "hi" ? field.titleHi : field.titleEn;
  const isTextarea = field.fieldType === "textarea";

  return (
    <div
      className={cn(
        "rounded-lg border p-3 transition",
        isEmpty && !isDirty
          ? "border-red-200 bg-red-50/30"
          : isDirty
          ? "border-amber-300 bg-amber-50/30"
          : "border-gray-200 bg-white"
      )}
    >
      <div className="flex items-center justify-between mb-1.5">
        <label className="text-xs font-medium text-gray-600 flex items-center gap-1.5">
          {label}
          <span className="text-[10px] text-gray-400 font-normal">
            ({field.fieldKey})
          </span>
          {isDirty && (
            <span className="text-[10px] text-amber-600 font-medium">
              {viewLang === "hi" ? "• बदला गया" : "• modified"}
            </span>
          )}
          {/* Gap #4: Empty value warning */}
          {isEmpty && (
            <span className="flex items-center gap-0.5 text-[10px] text-red-500 font-medium">
              <AlertTriangle className="h-3 w-3" />
              {viewLang === "hi" ? "खाली मान" : "empty value"}
            </span>
          )}
        </label>
        <div className="flex items-center gap-1">
          {/* Gap #2: History button */}
          <button
            onClick={onShowHistory}
            className="flex items-center gap-1 rounded px-2 py-1 text-[11px] font-medium text-gray-500 hover:bg-gray-100 transition"
            title={viewLang === "hi" ? "इतिहास देखें" : "View history"}
          >
            <History className="h-3 w-3" />
          </button>
          <button
            onClick={onTranslate}
            disabled={isTranslating || !aiAvailable}
            className="flex items-center gap-1 rounded px-2 py-1 text-[11px] font-medium text-indigo-600 hover:bg-indigo-50 transition disabled:opacity-50"
            title={
              !aiAvailable
                ? "एआई सेवा कॉन्फ़िगर नहीं है / AI service is not configured"
                : viewLang === "hi"
                  ? `हिन्दी → अंग्रेज़ी अनुवाद`
                  : `English → Hindi translate`
            }
          >
            {isTranslating ? (
              <Loader2 className="h-3 w-3 animate-spin" />
            ) : (
              <Languages className="h-3 w-3" />
            )}
            {viewLang === "hi" ? "अनुवाद → EN" : "Translate → HI"}
          </button>
        </div>
      </div>

      <div className="grid grid-cols-1 md:grid-cols-2 gap-2">
        {/* Current language (editable) */}
        <div>
          <span className="text-[10px] text-gray-400 uppercase font-semibold mb-0.5 block">
            {viewLang === "hi" ? "हिन्दी" : "English"} ({viewLang === "hi" ? "संपादन योग्य" : "editable"})
          </span>
          {isTextarea ? (
            <textarea
              value={value}
              onChange={(e) => onChangeValue(e.target.value)}
              rows={3}
              className={cn(
                "w-full border rounded-md px-2.5 py-1.5 text-sm focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none resize-none",
                !value.trim() ? "border-red-300" : "border-gray-300"
              )}
            />
          ) : (
            <input
              type="text"
              value={value}
              onChange={(e) => onChangeValue(e.target.value)}
              className={cn(
                "w-full border rounded-md px-2.5 py-1.5 text-sm focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none",
                !value.trim() ? "border-red-300" : "border-gray-300"
              )}
            />
          )}
        </div>

        {/* Other language (read-only preview) */}
        <div>
          <span className="text-[10px] text-gray-400 uppercase font-semibold mb-0.5 block">
            {viewLang === "hi" ? "English" : "हिन्दी"} ({viewLang === "hi" ? "preview" : "पूर्वावलोकन"})
          </span>
          <div
            className={cn(
              "w-full border rounded-md px-2.5 py-1.5 text-sm bg-gray-50 text-gray-600",
              !otherLangValue.trim() ? "border-red-200" : "border-gray-200",
              isTextarea ? "min-h-[76px]" : "min-h-[34px] flex items-center"
            )}
          >
            {otherLangValue || (
              <span className="text-gray-300 italic">
                {viewLang === "hi" ? "अनुवाद करें →" : "Translate →"}
              </span>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

/* ─── Gap #2: History Modal ─── */

function HistoryModal({
  fieldId,
  entries,
  isLoading,
  viewLang,
  onClose,
}: {
  fieldId: number;
  entries: CmsHistoryEntry[];
  isLoading: boolean;
  viewLang: "hi" | "en";
  onClose: () => void;
}) {
  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
      <div className="w-full max-w-lg bg-white rounded-xl shadow-xl p-6 max-h-[80vh] overflow-y-auto">
        <div className="flex items-center justify-between mb-4">
          <h3 className="text-lg font-semibold text-gray-900 flex items-center gap-2">
            <History className="h-5 w-5 text-indigo-600" />
            {viewLang === "hi" ? "परिवर्तन इतिहास" : "Change History"}
          </h3>
          <button
            onClick={onClose}
            className="text-gray-400 hover:text-gray-600 transition"
          >
            <X className="h-5 w-5" />
          </button>
        </div>

        {isLoading ? (
          <div className="flex items-center justify-center py-8">
            <Loader2 className="h-6 w-6 animate-spin text-indigo-500" />
          </div>
        ) : entries.length === 0 ? (
          <p className="text-center text-gray-500 py-8 text-sm">
            {viewLang === "hi" ? "कोई इतिहास नहीं मिला" : "No history found"}
          </p>
        ) : (
          <div className="space-y-3">
            {entries.map((entry) => (
              <div
                key={entry.id}
                className="rounded-lg border border-gray-200 p-3"
              >
                <div className="flex items-center justify-between mb-2">
                  <span className="text-xs font-medium text-gray-700">
                    {entry.changedByName || (viewLang === "hi" ? "अज्ञात" : "Unknown")}
                  </span>
                  <span className="text-xs text-gray-400">
                    {new Date(entry.changedAt).toLocaleString(
                      viewLang === "hi" ? "hi-IN" : "en-IN"
                    )}
                  </span>
                </div>
                <div className="grid grid-cols-2 gap-2 text-xs">
                  <div>
                    <span className="text-[10px] text-gray-400 uppercase font-semibold block mb-0.5">
                      हिन्दी
                    </span>
                    <p className="text-gray-700 bg-gray-50 rounded px-2 py-1 break-words">
                      {entry.valueHi || <span className="text-gray-300 italic">empty</span>}
                    </p>
                  </div>
                  <div>
                    <span className="text-[10px] text-gray-400 uppercase font-semibold block mb-0.5">
                      English
                    </span>
                    <p className="text-gray-700 bg-gray-50 rounded px-2 py-1 break-words">
                      {entry.valueEn || <span className="text-gray-300 italic">empty</span>}
                    </p>
                  </div>
                </div>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}
