"use client";

import { useState, useEffect, useCallback } from "react";
import {
  DndContext,
  closestCenter,
  PointerSensor,
  useSensor,
  useSensors,
  type DragEndEvent,
} from "@dnd-kit/core";
import {
  SortableContext,
  useSortable,
  verticalListSortingStrategy,
  arrayMove,
} from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { Card, Toggle } from "@/shared/components";
import { cn } from "@/shared/utils/cn";
import { useTranslations } from "next-intl";
import {
  HIDDEN_SIDEBAR_GROUP_LABELS_SETTING_KEY,
  HIDEABLE_SIDEBAR_GROUP_IDS,
  normalizeHiddenSidebarGroupLabels,
  type HideableSidebarGroupId,
} from "@/shared/constants/sidebarGroupVisibility";
import {
  HIDDEN_SIDEBAR_ITEMS_SETTING_KEY,
  SIDEBAR_SECTION_ORDER_KEY,
  SIDEBAR_ITEM_ORDER_KEY,
  SIDEBAR_PRESET_KEY,
  SIDEBAR_SETTINGS_UPDATED_EVENT,
  SIDEBAR_SECTIONS,
  SIDEBAR_PRESETS,
  applySectionOrder,
  applyItemOrder,
  normalizeHiddenSidebarItems,
  type HideableSidebarItemId,
  type SidebarSectionId,
  type SidebarItemOrder,
  type SidebarPresetId,
  type SidebarSectionDefinition,
  type SidebarSectionChild,
  type SidebarItemDefinition,
  type SidebarItemGroup,
} from "@/shared/constants/sidebarVisibility";

// ─── Sortable section row ──────────────────────────────────────────────────────

interface SortableSectionProps {
  section: SidebarSectionDefinition & { title: string };
  hiddenSet: Set<HideableSidebarItemId>;
  hiddenGroupLabelsSet: Set<HideableSidebarGroupId>;
  itemOrder: string[];
  onToggleItem: (id: HideableSidebarItemId) => void;
  onToggleGroupLabel: (id: HideableSidebarGroupId) => void;
  onItemReorder: (sectionId: SidebarSectionId, newOrder: string[]) => void;
  getLabel: (key: string, fallback: string) => string;
}

function SortableSection({
  section,
  hiddenSet,
  hiddenGroupLabelsSet,
  itemOrder,
  onToggleItem,
  onToggleGroupLabel,
  onItemReorder,
  getLabel,
}: SortableSectionProps) {
  const tSidebar = useTranslations("sidebar");
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
    id: section.id,
  });
  const style = { transform: CSS.Transform.toString(transform), transition };

  const [expanded, setExpanded] = useState(true);

  const allChildren = section.children as SidebarSectionChild[];
  const getChildId = (c: SidebarSectionChild) =>
    "type" in c && c.type === "group" ? c.id : (c as SidebarItemDefinition).id;

  const orderedChildren = applyItemOrder(allChildren, itemOrder);
  const childIds = orderedChildren.map(getChildId);
  const sensors = useSensors(useSensor(PointerSensor));

  const handleItemDragEnd = (event: DragEndEvent) => {
    const { active, over } = event;
    if (!over || active.id === over.id) return;
    const oldIdx = childIds.indexOf(active.id as string);
    const newIdx = childIds.indexOf(over.id as string);
    if (oldIdx === -1 || newIdx === -1) return;
    onItemReorder(section.id as SidebarSectionId, arrayMove(childIds, oldIdx, newIdx));
  };

  return (
    <div
      ref={setNodeRef}
      style={style}
      className={cn(
        "rounded-lg border border-border bg-surface/40 transition-shadow",
        isDragging && "shadow-lg opacity-80"
      )}
    >
      {/* Section header */}
      <div className="flex items-center gap-2 px-4 py-3 border-b border-border/70">
        <button
          {...listeners}
          {...attributes}
          className="text-text-muted/40 hover:text-text-muted/80 cursor-grab active:cursor-grabbing touch-none shrink-0"
          title={tSidebar("dragReorderSection")}
          aria-label={tSidebar("dragReorderSection")}
        >
          <span className="material-symbols-outlined text-[18px]">drag_indicator</span>
        </button>
        <button
          onClick={() => setExpanded((p) => !p)}
          className="flex-1 flex items-center gap-2 text-left"
        >
          <span className="text-xs font-semibold uppercase tracking-wider text-text-muted/70">
            {section.title}
          </span>
          <span
            className={cn(
              "material-symbols-outlined text-[14px] text-text-muted/40 transition-transform ml-auto",
              expanded && "rotate-180"
            )}
          >
            expand_more
          </span>
        </button>
      </div>

      {/* Section children with inner DnD */}
      {expanded && (
        <DndContext
          sensors={sensors}
          collisionDetection={closestCenter}
          onDragEnd={handleItemDragEnd}
        >
          <SortableContext items={childIds} strategy={verticalListSortingStrategy}>
            <div className="divide-y divide-border/70">
              {orderedChildren.map((child) => {
                if ("type" in child && child.type === "group") {
                  const group = child as SidebarItemGroup;
                  return (
                    <SortableChildRow key={group.id} id={group.id}>
                      <GroupRow
                        group={group}
                        hiddenSet={hiddenSet}
                        hiddenGroupLabelsSet={hiddenGroupLabelsSet}
                        onToggleItem={onToggleItem}
                        onToggleGroupLabel={onToggleGroupLabel}
                        getLabel={getLabel}
                      />
                    </SortableChildRow>
                  );
                }
                const item = child as SidebarItemDefinition;
                return (
                  <SortableChildRow key={item.id} id={item.id}>
                    <ItemRow
                      item={item}
                      hiddenSet={hiddenSet}
                      onToggleItem={onToggleItem}
                      getLabel={getLabel}
                    />
                  </SortableChildRow>
                );
              })}
            </div>
          </SortableContext>
        </DndContext>
      )}
    </div>
  );
}

// ─── Sortable child row wrapper ────────────────────────────────────────────────

function SortableChildRow({ id, children }: { id: string; children: React.ReactNode }) {
  const tSidebar = useTranslations("sidebar");
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
    id,
  });
  const style = { transform: CSS.Transform.toString(transform), transition };
  return (
    <div
      ref={setNodeRef}
      style={style}
      className={cn("flex items-start gap-2", isDragging && "opacity-60")}
    >
      <button
        {...listeners}
        {...attributes}
        className="mt-3.5 ml-4 text-text-muted/30 hover:text-text-muted/70 cursor-grab active:cursor-grabbing touch-none shrink-0"
        title={tSidebar("dragReorderItem")}
        aria-label={tSidebar("dragReorderItem")}
      >
        <span className="material-symbols-outlined text-[14px]">drag_indicator</span>
      </button>
      <div className="flex-1 min-w-0">{children}</div>
    </div>
  );
}

// ─── Item row ─────────────────────────────────────────────────────────────────

interface ItemRowProps {
  item: SidebarItemDefinition;
  hiddenSet: Set<HideableSidebarItemId>;
  onToggleItem: (id: HideableSidebarItemId) => void;
  getLabel: (key: string, fallback: string) => string;
}

// Items that must always remain visible (safety guard)
const PROTECTED_ITEM_IDS = new Set(["settings-sidebar"]);

function ItemRow({ item, hiddenSet, onToggleItem, getLabel }: ItemRowProps) {
  const tSidebar = useTranslations("sidebar");
  const isProtected = PROTECTED_ITEM_IDS.has(item.id);
  return (
    <div className="flex items-center justify-between gap-4 px-4 py-3">
      <div className="flex items-center gap-2 min-w-0">
        <span className="material-symbols-outlined text-[16px] text-text-muted/50 shrink-0">
          {item.icon}
        </span>
        <p className="font-medium truncate">{getLabel(item.i18nKey, item.id)}</p>
      </div>
      {isProtected ? (
        <span
          className="material-symbols-outlined text-[16px] text-text-muted/40"
          title={tSidebar("cannotHide")}
          aria-label={tSidebar("alwaysVisible")}
        >
          lock
        </span>
      ) : (
        <Toggle checked={!hiddenSet.has(item.id)} onChange={() => onToggleItem(item.id)} />
      )}
    </div>
  );
}

// ─── Group row (items inside group, no sub-DnD) ───────────────────────────────

interface GroupRowProps {
  group: SidebarItemGroup;
  hiddenSet: Set<HideableSidebarItemId>;
  hiddenGroupLabelsSet: Set<HideableSidebarGroupId>;
  onToggleItem: (id: HideableSidebarItemId) => void;
  onToggleGroupLabel: (id: HideableSidebarGroupId) => void;
  getLabel: (key: string, fallback: string) => string;
}

function GroupRow({
  group,
  hiddenSet,
  hiddenGroupLabelsSet,
  onToggleItem,
  onToggleGroupLabel,
  getLabel,
}: GroupRowProps) {
  const [open, setOpen] = useState(true);
  const groupId = group.id as HideableSidebarGroupId;
  const canToggleSeparator = HIDEABLE_SIDEBAR_GROUP_IDS.includes(groupId);
  const separatorVisible = !hiddenGroupLabelsSet.has(groupId);
  const separatorLabel = getLabel("groupSeparatorLabel", "Separator");

  return (
    <div className="w-full">
      <div className="flex items-center gap-2 px-4 py-2.5 hover:bg-black/5 dark:hover:bg-white/5 transition-colors">
        <button
          onClick={() => setOpen((p) => !p)}
          className="flex min-w-0 flex-1 items-center gap-2 text-left"
        >
          <span
            className={cn(
              "material-symbols-outlined text-[12px] text-text-muted/40 transition-transform",
              open && "rotate-90"
            )}
          >
            chevron_right
          </span>
          <span className="truncate text-[10px] font-semibold uppercase tracking-widest text-text-muted/50">
            {getLabel(group.titleKey, group.titleFallback)}
          </span>
        </button>
        <span className="text-xs text-text-muted/40">
          {group.items.filter((i) => !hiddenSet.has(i.id)).length}/{group.items.length}
        </span>
        {canToggleSeparator && (
          <div className="flex items-center gap-2 border-l border-border/60 pl-3">
            <span className="text-[10px] font-medium text-text-muted/50">{separatorLabel}</span>
            <Toggle
              size="sm"
              checked={separatorVisible}
              onChange={() => onToggleGroupLabel(groupId)}
            />
          </div>
        )}
      </div>
      {open && (
        <div className="divide-y divide-border/50 pl-2">
          {group.items.map((item) => (
            <div key={item.id} className="flex items-center justify-between gap-4 px-4 py-2.5">
              <div className="flex items-center gap-2 min-w-0">
                <span className="material-symbols-outlined text-[14px] text-text-muted/40 shrink-0">
                  {item.icon}
                </span>
                <p className="text-sm font-medium truncate">{getLabel(item.i18nKey, item.id)}</p>
              </div>
              <Toggle
                size="sm"
                checked={!hiddenSet.has(item.id)}
                onChange={() => onToggleItem(item.id)}
              />
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ─── Main component ───────────────────────────────────────────────────────────

export default function SidebarTab() {
  const t = useTranslations("settings");
  const tSidebar = useTranslations("sidebar");

  const getLabel = useCallback(
    (key: string, fallback: string) =>
      typeof tSidebar.has === "function" && tSidebar.has(key) ? tSidebar(key) : fallback,
    [tSidebar]
  );
  const getSettingsLabel = useCallback(
    (key: string, fallback: string) =>
      typeof t.has === "function" && t.has(key) ? t(key) : fallback,
    [t]
  );

  const [loading, setLoading] = useState(true);
  const [hiddenSidebarItems, setHiddenSidebarItems] = useState<HideableSidebarItemId[]>([]);
  const [hiddenSidebarGroupLabels, setHiddenSidebarGroupLabels] = useState<
    HideableSidebarGroupId[]
  >([]);
  const [sectionOrder, setSectionOrder] = useState<SidebarSectionId[]>([]);
  const [itemOrder, setItemOrder] = useState<SidebarItemOrder>({});
  const [activePreset, setActivePreset] = useState<SidebarPresetId | null>(null);
  const [confirmPreset, setConfirmPreset] = useState<SidebarPresetId | null>(null);
  const [showDebug, setShowDebug] = useState(false);

  useEffect(() => {
    fetch("/api/settings")
      .then((r) => r.json())
      .then((data) => {
        setHiddenSidebarItems(
          normalizeHiddenSidebarItems(data?.[HIDDEN_SIDEBAR_ITEMS_SETTING_KEY])
        );
        setHiddenSidebarGroupLabels(
          normalizeHiddenSidebarGroupLabels(data?.[HIDDEN_SIDEBAR_GROUP_LABELS_SETTING_KEY])
        );
        setSectionOrder(
          Array.isArray(data?.[SIDEBAR_SECTION_ORDER_KEY]) ? data[SIDEBAR_SECTION_ORDER_KEY] : []
        );
        setItemOrder(
          data?.[SIDEBAR_ITEM_ORDER_KEY] && typeof data[SIDEBAR_ITEM_ORDER_KEY] === "object"
            ? data[SIDEBAR_ITEM_ORDER_KEY]
            : {}
        );
        setActivePreset(data?.[SIDEBAR_PRESET_KEY] ?? null);
        setShowDebug(data?.debugMode === true);
        setLoading(false);
      })
      .catch(() => setLoading(false));
  }, []);

  const patch = async (updates: Record<string, unknown>) => {
    try {
      const res = await fetch("/api/settings", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(updates),
      });
      if (res.ok) {
        window.dispatchEvent(new CustomEvent(SIDEBAR_SETTINGS_UPDATED_EVENT, { detail: updates }));
      } else {
        console.error("Failed to update sidebar settings:", res.statusText);
      }
    } catch (err) {
      console.error("Error updating sidebar settings:", err);
    }
  };

  const toggleItem = (id: HideableSidebarItemId) => {
    // Protected items can never be hidden
    if (PROTECTED_ITEM_IDS.has(id)) return;
    const next = hiddenSidebarItems.includes(id)
      ? hiddenSidebarItems.filter((x) => x !== id)
      : [...hiddenSidebarItems, id];
    setHiddenSidebarItems(next);
    // Any manual change → custom mode
    setActivePreset(null);
    patch({ [HIDDEN_SIDEBAR_ITEMS_SETTING_KEY]: next, [SIDEBAR_PRESET_KEY]: null });
  };

  const hiddenSet = new Set(hiddenSidebarItems);
  const hiddenGroupLabelsSet = new Set(hiddenSidebarGroupLabels);

  const toggleGroupLabel = (id: HideableSidebarGroupId) => {
    const next = hiddenSidebarGroupLabels.includes(id)
      ? hiddenSidebarGroupLabels.filter((x) => x !== id)
      : [...hiddenSidebarGroupLabels, id];
    setHiddenSidebarGroupLabels(next);
    setActivePreset(null);
    patch({ [HIDDEN_SIDEBAR_GROUP_LABELS_SETTING_KEY]: next, [SIDEBAR_PRESET_KEY]: null });
  };

  const visibleSections = SIDEBAR_SECTIONS.filter((s) => s.visibility !== "debug" || showDebug).map(
    (s) => ({ ...s, title: getLabel(s.titleKey, s.titleFallback) })
  );

  const orderedSections = applySectionOrder(visibleSections, sectionOrder);

  const sectionIds = orderedSections.map((s) => s.id);

  const sensors = useSensors(useSensor(PointerSensor));

  const handleSectionDragEnd = (event: DragEndEvent) => {
    const { active, over } = event;
    if (!over || active.id === over.id) return;
    const oldIdx = sectionIds.indexOf(active.id as SidebarSectionId);
    const newIdx = sectionIds.indexOf(over.id as SidebarSectionId);
    if (oldIdx === -1 || newIdx === -1) return;
    const newOrder = arrayMove(sectionIds, oldIdx, newIdx) as SidebarSectionId[];
    setSectionOrder(newOrder);
    setActivePreset(null);
    patch({ [SIDEBAR_SECTION_ORDER_KEY]: newOrder, [SIDEBAR_PRESET_KEY]: null });
  };

  const handleItemReorder = (sectionId: SidebarSectionId, newOrder: string[]) => {
    const next = { ...itemOrder, [sectionId]: newOrder };
    setItemOrder(next);
    setActivePreset(null);
    patch({ [SIDEBAR_ITEM_ORDER_KEY]: next, [SIDEBAR_PRESET_KEY]: null });
  };

  const applyPreset = (presetId: SidebarPresetId) => {
    const preset = SIDEBAR_PRESETS.find((p) => p.id === presetId);
    if (!preset) return;
    // Ensure protected items are never hidden, even if a preset includes them
    const safeHidden = preset.hiddenItems.filter((id) => !PROTECTED_ITEM_IDS.has(id));
    setHiddenSidebarItems(safeHidden);
    setHiddenSidebarGroupLabels([]);
    setSectionOrder([]);
    setItemOrder({});
    setActivePreset(presetId);
    setConfirmPreset(null);
    patch({
      [HIDDEN_SIDEBAR_ITEMS_SETTING_KEY]: safeHidden,
      [HIDDEN_SIDEBAR_GROUP_LABELS_SETTING_KEY]: [],
      [SIDEBAR_SECTION_ORDER_KEY]: [],
      [SIDEBAR_ITEM_ORDER_KEY]: {},
      [SIDEBAR_PRESET_KEY]: presetId,
    });
  };

  const resetToDefault = () => applyPreset("all");

  const presetLabels: Record<SidebarPresetId, string> = {
    all: getSettingsLabel("presetAll", "All"),
    minimal: getSettingsLabel("presetMinimal", "Minimal"),
    developer: getSettingsLabel("presetDeveloper", "Developer"),
    admin: getSettingsLabel("presetAdmin", "Admin"),
  };

  const presetDescriptions: Record<SidebarPresetId, string> = {
    all: getSettingsLabel("presetAllDesc", "Show everything"),
    minimal: getSettingsLabel("presetMinimalDesc", "Core pages only"),
    developer: getSettingsLabel("presetDeveloperDesc", "Dev & proxy tools"),
    admin: getSettingsLabel("presetAdminDesc", "Monitoring & audit"),
  };

  return (
    <Card>
      <div className="flex items-center gap-3 mb-4">
        <div className="p-2 rounded-lg bg-indigo-500/10 text-indigo-500">
          <span className="material-symbols-outlined text-[20px]" aria-hidden="true">
            view_sidebar
          </span>
        </div>
        <div>
          <h3 className="text-lg font-semibold">
            {getSettingsLabel("settingsSidebarTitle", "Sidebar Customization")}
          </h3>
          <p className="text-sm text-text-muted">
            {getSettingsLabel(
              "settingsSidebarDesc",
              "Control which items appear in the sidebar and their order"
            )}
          </p>
        </div>
      </div>

      <div className="flex flex-col gap-6">
        {/* Presets */}
        <div>
          <div className="mb-3">
            <p className="font-medium">{getSettingsLabel("sidebarPresets", "Presets")}</p>
            <p className="text-sm text-text-muted">
              {getSettingsLabel(
                "sidebarPresetsDesc",
                "Start from a role-based layout. Any change after applying a preset switches to Custom."
              )}
            </p>
          </div>

          {/* Active preset badge */}
          <div className="mb-3 flex items-center gap-2 text-sm">
            <span className="text-text-muted">
              {getSettingsLabel("activePresetLabel", "Active:")}
            </span>
            <span
              className={cn(
                "px-2 py-0.5 rounded-full text-xs font-medium",
                activePreset
                  ? "bg-primary/10 text-primary"
                  : "bg-surface border border-border text-text-muted"
              )}
            >
              {activePreset
                ? presetLabels[activePreset]
                : getSettingsLabel("presetCustom", "Custom")}
            </span>
          </div>

          <div className="grid grid-cols-2 sm:grid-cols-4 gap-2">
            {SIDEBAR_PRESETS.map((preset) => {
              const isActive = activePreset === preset.id;
              return (
                <button
                  key={preset.id}
                  disabled={loading}
                  onClick={() => {
                    if (activePreset === preset.id) return;
                    if (
                      activePreset !== null ||
                      hiddenSidebarItems.length > 0 ||
                      hiddenSidebarGroupLabels.length > 0 ||
                      sectionOrder.length > 0
                    ) {
                      setConfirmPreset(preset.id);
                    } else {
                      applyPreset(preset.id);
                    }
                  }}
                  className={cn(
                    "flex flex-col items-center gap-1.5 p-3 rounded-lg border transition-colors disabled:opacity-60",
                    isActive
                      ? "border-primary bg-primary/10 text-primary"
                      : "border-border hover:border-primary/40 bg-surface/40 text-text-main"
                  )}
                >
                  <span
                    className="material-symbols-outlined text-[22px]"
                    style={isActive ? { fontVariationSettings: "'FILL' 1" } : {}}
                    aria-hidden="true"
                  >
                    {preset.icon}
                  </span>
                  <span className="text-sm font-semibold">{presetLabels[preset.id]}</span>
                  <span
                    className={cn(
                      "text-[10px] text-center",
                      isActive ? "text-primary/70" : "text-text-muted"
                    )}
                  >
                    {presetDescriptions[preset.id]}
                  </span>
                </button>
              );
            })}
          </div>

          {/* Confirm preset dialog */}
          {confirmPreset && (
            <div className="mt-3 p-3 rounded-lg border border-amber-500/30 bg-amber-500/5 flex items-center gap-3">
              <span className="material-symbols-outlined text-amber-500 text-[18px] shrink-0">
                warning
              </span>
              <p className="text-sm flex-1">
                {getSettingsLabel(
                  "presetConfirmWarning",
                  `Applying "${presetLabels[confirmPreset]}" will replace your current visibility and order settings.`
                )}
              </p>
              <div className="flex gap-2 shrink-0">
                <button
                  onClick={() => setConfirmPreset(null)}
                  className="px-3 py-1.5 text-sm rounded-md border border-border hover:bg-surface/80 transition-colors"
                >
                  {getSettingsLabel("cancelLabel", "Cancel")}
                </button>
                <button
                  onClick={() => applyPreset(confirmPreset)}
                  className="px-3 py-1.5 text-sm rounded-md bg-primary text-white hover:bg-primary/90 transition-colors"
                >
                  {getSettingsLabel("applyLabel", "Apply")}
                </button>
              </div>
            </div>
          )}
        </div>

        {/* Visibility & order */}
        <div>
          <div className="mb-3 flex items-start justify-between gap-4">
            <div>
              <p className="font-medium">
                {getSettingsLabel("sidebarOrder", "Visibility & Order")}
              </p>
              <p className="text-sm text-text-muted">
                {getSettingsLabel(
                  "sidebarOrderDesc",
                  "Toggle items on/off and drag to reorder sections and their entries."
                )}
              </p>
            </div>
            <button
              onClick={resetToDefault}
              disabled={loading}
              className="shrink-0 text-sm text-text-muted hover:text-text-main border border-border rounded-md px-3 py-1.5 hover:bg-surface/80 transition-colors disabled:opacity-50"
            >
              {getSettingsLabel("resetDefault", "Reset to default")}
            </button>
          </div>

          <div className="flex flex-col gap-3">
            <DndContext
              sensors={sensors}
              collisionDetection={closestCenter}
              onDragEnd={handleSectionDragEnd}
            >
              <SortableContext items={sectionIds} strategy={verticalListSortingStrategy}>
                {orderedSections.map((section) => (
                  <SortableSection
                    key={section.id}
                    section={section}
                    hiddenSet={hiddenSet}
                    hiddenGroupLabelsSet={hiddenGroupLabelsSet}
                    itemOrder={itemOrder[section.id as SidebarSectionId] ?? []}
                    onToggleItem={toggleItem}
                    onToggleGroupLabel={toggleGroupLabel}
                    onItemReorder={handleItemReorder}
                    getLabel={getLabel}
                  />
                ))}
              </SortableContext>
            </DndContext>
          </div>

          <p className="mt-3 text-xs text-text-muted">
            {getSettingsLabel(
              "sidebarVisibilityHint",
              "A sidebar section hides automatically when all of its entries are hidden"
            )}
          </p>
        </div>
      </div>
    </Card>
  );
}
