import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { adminApi, adminEndpoints } from "../api";
import type { ComponentRecord } from "../types";
import type { PageBlock, PageRecord, PageSection } from "../types";
import {
  blockInsertFailureMessage,
  placePageBlock,
  type BlockInsertResult,
  type SectionWithSlots,
} from "@/lib/placePageBlock";
import { GripVertical, Trash2, ChevronDown, ChevronUp, ChevronRight, ArrowLeft, Plus, X, Pencil, Copy, Settings2 } from "lucide-react";
import {
  SECTION_LAYOUTS,
  normalizeContent,
  getColumnCount,
  serializeSectionBlocks,
  sectionBlocksForEditor,
} from "./sectionLayouts";
import { SectionStyleEditForm } from "../components/SectionStyleEditForm";
import { PageSectionRenderer } from "@/components/PageSectionRenderer";
import { SiteChromeFrame } from "@/components/SiteChromeFrame";
import { normalizeSectionStyle, type EditorPreviewBreakpoint } from "@/lib/sectionStyle";
import type { SectionStyleSettings } from "../types";
import { getBlockComponent } from "@/components/page-blocks";
import { GradeHeroBlock } from "@/components/page-blocks/GradeHeroBlock";
import { cloneBlockContent } from "@/lib/cloneBlockContent";
import {
  collectCompetitionNavState,
  type CompetitionNavItem,
} from "@/lib/competitionNavigation";
import { copyTextToClipboard, isClipboardReadAvailable, readTextFromClipboard } from "@/lib/clipboard";
import { isHomepageSlug, normalizePageSlug, slugForApiPayload, slugForDisplay } from "@/lib/pageSlug";
import { resolveBlockSlug } from "@/lib/blockSlug";
import {
  buildContentPlaceholderVars,
} from "@/lib/contentPlaceholders";
import {
  findComponentLibraryContent,
  resolveEditorBlockContent,
} from "@/lib/mergeBlockContent";
import { COMPONENT_LIBRARY_UPDATED_EVENT } from "@/lib/componentDefaults";
import {
  normalizePageSettings,
  resolveShowFooter,
  shouldHideGlobalFooter,
  shouldRenderFooterBlock,
} from "@/lib/pageFooterSettings";
import { SITE_SETTINGS_UPDATED_EVENT } from "@/lib/siteSettings";
import { useSiteSettings } from "@/contexts/SiteSettingsContext";
import {
  PASTE_COMPONENT_CLIPBOARD_EMPTY_ERROR,
  parsePastedComponentJson,
} from "@/lib/pasteComponent";
import { createPageBlockInstanceId } from "@/lib/pageBlockInstance";
import { pasteDebug, pasteLogError } from "@/lib/pasteDebug";
import { normalizePastedText } from "@/lib/pasteText";
import { BlockEditForm } from "./BlockEditForm";
import ComponentPickerModal, { type ComponentPickerTarget } from "../components/ComponentPickerModal";
import PasteComponentJsonModal from "../components/PasteComponentJsonModal";

function BlockEditor({
  block,
  index,
  onUpdate,
  onRemove,
  onMoveUp,
  onMoveDown,
  canMoveUp,
  canMoveDown,
  onError,
}: {
  block: PageBlock;
  index: number;
  onUpdate: (content: Record<string, unknown>) => void;
  onRemove: () => void;
  onMoveUp: () => void;
  onMoveDown: () => void;
  canMoveUp: boolean;
  canMoveDown: boolean;
  onError?: (message: string) => void;
}) {
  const [expanded, setExpanded] = useState(true);
  const [contentJson, setContentJson] = useState(() => JSON.stringify(block.content ?? {}, null, 2));
  const [dirty, setDirty] = useState(false);
  const contentJsonRef = useRef(contentJson);
  contentJsonRef.current = contentJson;

  useEffect(() => {
    setContentJson(JSON.stringify(block.content ?? {}, null, 2));
  }, [block.content]);

  const applyContent = useCallback(() => {
    try {
      const content = JSON.parse(contentJson || "{}");
      onUpdate(content);
      setDirty(false);
    } catch {
      onError?.("Content must be valid JSON.");
    }
  }, [contentJson, onUpdate, onError]);

  // Auto-apply block content after user stops typing so page auto-save can run
  useEffect(() => {
    if (!dirty) return;
    const t = window.setTimeout(() => {
      try {
        const content = JSON.parse(contentJsonRef.current || "{}");
        onUpdate(content);
        setDirty(false);
      } catch {
        onError?.("Content must be valid JSON.");
      }
    }, 1200);
    return () => window.clearTimeout(t);
  }, [contentJson, dirty, onUpdate, onError]);

  return (
    <div
      style={{
        background: "#fff",
        borderRadius: 12,
        boxShadow: "0 1px 2px rgba(0,0,0,0.05)",
        overflow: "hidden",
        marginBottom: 12,
        border: "1px solid #e5e7eb",
      }}
    >
      <div
        style={{
          display: "flex",
          alignItems: "center",
          justifyContent: "space-between",
          padding: "12px 16px",
          background: "#f8fafc",
          borderBottom: "1px solid #e5e7eb",
          cursor: "pointer",
        }}
        onClick={() => setExpanded((e) => !e)}
      >
        <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
          <GripVertical size={18} style={{ color: "#94a3b8" }} />
          <span style={{ fontWeight: 600 }}>{block.componentName}</span>
          <span style={{ color: "#64748b", fontSize: 13 }}>(component #{block.componentId})</span>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 4 }} onClick={(e) => e.stopPropagation()}>
          <button type="button" onClick={onMoveUp} disabled={!canMoveUp} style={{ padding: 4, border: "none", background: "none", cursor: canMoveUp ? "pointer" : "not-allowed" }}>
            <ChevronUp size={20} />
          </button>
          <button type="button" onClick={onMoveDown} disabled={!canMoveDown} style={{ padding: 4, border: "none", background: "none", cursor: canMoveDown ? "pointer" : "not-allowed" }}>
            <ChevronDown size={20} />
          </button>
          <button type="button" onClick={onRemove} style={{ padding: 4, color: "#b91c1c", border: "none", background: "none", cursor: "pointer" }}>
            <Trash2 size={18} />
          </button>
          {expanded ? <ChevronDown size={20} /> : <ChevronUp size={20} />}
        </div>
      </div>
      {expanded && (
        <div style={{ padding: 16 }}>
          <label style={{ display: "block", marginBottom: 8, fontWeight: 500, fontSize: 14, color: "#374151" }}>Content (edit for this page)</label>
          <textarea
            value={contentJson}
            onChange={(e) => { setContentJson(e.target.value); setDirty(true); }}
            rows={8}
            style={{ width: "100%", padding: "12px 14px", border: "1px solid #e5e7eb", borderRadius: 10, boxSizing: "border-box", fontFamily: "monospace", fontSize: 13, outline: "none" }}
          />
          {dirty && (
            <button type="button" onClick={applyContent} style={{ marginTop: 10, padding: "10px 18px", background: "#0f172a", color: "#fff", border: "none", borderRadius: 10, cursor: "pointer", fontWeight: 500 }}>
              Apply content
            </button>
          )}
        </div>
      )}
    </div>
  );
}

function SectionInsertDivider({ onClick, label = "Add section here" }: { onClick: () => void; label?: string }) {
  return (
    <div className="page-editor-section-insert">
      <button type="button" className="page-editor-section-insert-btn" onClick={onClick}>
        <Plus size={16} aria-hidden />
        {label}
      </button>
    </div>
  );
}

export default function PageEditor() {
  const { id } = useParams<{ id: string }>();
  const isNew = id === "new" || id === undefined;
  const navigate = useNavigate();
  const [page, setPage] = useState<PageRecord | null>(null);
  const [title, setTitle] = useState("");
  const [slug, setSlug] = useState("");
  const [status, setStatus] = useState("draft");
  const [showFooter, setShowFooter] = useState(true);
  const [sections, setSections] = useState<SectionWithSlots[]>([]);
  const [saving, setSaving] = useState(false);
  const [loadError, setLoadError] = useState("");
  const [components, setComponents] = useState<ComponentRecord[]>([]);
  const [pasteError, setPasteError] = useState("");
  const [componentPickerTarget, setComponentPickerTarget] = useState<ComponentPickerTarget | null>(null);
  const [sectionModalOpen, setSectionModalOpen] = useState(false);
  const [sectionInsertIndex, setSectionInsertIndex] = useState(0);
  const [sectionWidth, setSectionWidth] = useState<"full" | "container">("container");
  const [sectionLayout, setSectionLayout] = useState<PageSection["layout"]>("100");
  const [toast, setToast] = useState<{ type: "error" | "success" | "info"; message: string } | null>(null);
  const [editingBlock, setEditingBlock] = useState<{ sectionIndex: number; blockIndex: number } | null>(null);
  const [editingSectionIndex, setEditingSectionIndex] = useState<number | null>(null);
  const [sectionPreviewBp, setSectionPreviewBp] = useState<Record<number, EditorPreviewBreakpoint>>({});
  const [collapsedSections, setCollapsedSections] = useState<Set<number>>(new Set());
  const [manualPasteOpen, setManualPasteOpen] = useState(false);
  const [manualPasteTarget, setManualPasteTarget] = useState<{ sectionIndex?: number; slotIndex?: number } | null>(null);
  const [pasteModalInitial, setPasteModalInitial] = useState<{
    text: string;
    error: string;
    step: "paste" | "preview";
  }>({ text: "", error: "", step: "paste" });
  const [blockPreviewRevision, setBlockPreviewRevision] = useState<Record<string, number>>({});
  const lastSavedRef = useRef<{ title: string; slug: string; status: string; sectionsJson: string; showFooter: boolean } | null>(null);
  const loadCompleteForIdRef = useRef<number | null>(null);
  const sectionsRef = useRef(sections);
  const componentsRef = useRef(components);
  const pendingScrollSectionIndexRef = useRef<number | null>(null);
  sectionsRef.current = sections;
  componentsRef.current = components;

  const toggleSectionCollapsed = (sectionIndex: number) => {
    setCollapsedSections((prev) => {
      const next = new Set(prev);
      if (next.has(sectionIndex)) next.delete(sectionIndex);
      else next.add(sectionIndex);
      return next;
    });
  };

  const getBlockSlug = (block: PageBlock): string => resolveBlockSlug(block, components);

  const placeholderVars = useMemo(
    () => buildContentPlaceholderVars(sections as PageSection[], { pageTitle: title }),
    [sections, title]
  );
  const competitionComponentLookup = useMemo(
    () => components.map((component) => ({
      id: component.id,
      name: component.name || component.slug,
      slug: component.slug,
    })),
    [components],
  );
  const resolveCompetitionBlockSlug = useCallback(
    (block: { componentId?: number; componentSlug?: string; componentName?: string }) => (
      resolveBlockSlug({
        componentId: block.componentId ?? 0,
        componentName: block.componentName ?? "",
        componentSlug: block.componentSlug,
      }, components)
    ),
    [components],
  );
  const competitionNavState = useMemo(() => {
    const flatBlocks = sections.flatMap((section) =>
      (section.blocks ?? []).filter((block): block is PageBlock => block != null),
    );
    return collectCompetitionNavState(
      flatBlocks,
      competitionComponentLookup,
      resolveCompetitionBlockSlug,
    );
  }, [sections, competitionComponentLookup, resolveCompetitionBlockSlug]);
  const competitionNavSignature = useMemo(
    () => JSON.stringify({
      defaultTargetSlug: competitionNavState.defaultTargetSlug,
      items: competitionNavState.items.map((item) => [item.id, item.targetComponent]),
      targetSlugs: competitionNavState.targetSlugs,
    }),
    [competitionNavState.defaultTargetSlug, competitionNavState.items, competitionNavState.targetSlugs],
  );
  // Editor only tracks the active nav id for the Grade Hero tab highlight.
  // It never hides competition components in the Page Builder.
  const [activeCompetitionNavId, setActiveCompetitionNavId] = useState(
    competitionNavState.items[0]?.id ?? "",
  );
  useEffect(() => {
    try {
      const parsed = JSON.parse(competitionNavSignature) as {
        items?: Array<[string, string]>;
      };
      setActiveCompetitionNavId(parsed.items?.[0]?.[0] ?? "");
    } catch {
      setActiveCompetitionNavId("");
    }
  }, [competitionNavSignature]);
  const handleCompetitionNavClick = useCallback((item: CompetitionNavItem) => {
    setActiveCompetitionNavId(item.id);
  }, []);
  const { settings: siteSettings } = useSiteSettings();
  const siteChromeKey = `${siteSettings.header_layout}-${siteSettings.footer_layout}`;
  const hasPageFooter = useMemo(
    () => shouldHideGlobalFooter(sections as PageSection[], { showFooter }),
    [sections, showFooter]
  );
  const pageSettings = useMemo(() => ({ showFooter }), [showFooter]);

  const showToast = (message: string, type: "error" | "success" | "info" = "error") => {
    setToast({ type, message });
    window.setTimeout(() => setToast(null), 4000);
  };

  const loadPage = useCallback(async () => {
    if (isNew || !id || id === "new") return;
    const numId = Number(id);
    if (Number.isNaN(numId)) return;
    try {
      const data = await adminApi.get<{ page: PageRecord }>(adminEndpoints.page(numId));
      setPage(data.page);
      setTitle(data.page.title);
      setSlug(slugForDisplay(data.page.slug));
      setStatus(data.page.status);
      const normalizedSections = normalizeContent(data.page.content).map((s) => ({
        ...s,
        blocks: sectionBlocksForEditor(s),
      }));
      setSections(normalizedSections);
      setShowFooter(resolveShowFooter(normalizePageSettings(data.page.settings)));
    } catch (e) {
      setLoadError(e instanceof Error ? e.message : "Failed to load page");
    }
  }, [id, isNew]);

  const loadComponents = useCallback(async () => {
    try {
      const data = await adminApi.get<{ components: ComponentRecord[] }>(adminEndpoints.components);
      setComponents(data.components ?? []);
    } catch {
      setComponents([]);
    }
  }, []);

  useEffect(() => {
    loadPage();
    loadComponents();
  }, [loadPage, loadComponents]);

  useEffect(() => {
    const refreshLibrary = () => {
      void loadComponents();
    };
    window.addEventListener("focus", refreshLibrary);
    window.addEventListener(SITE_SETTINGS_UPDATED_EVENT, refreshLibrary);
    window.addEventListener(COMPONENT_LIBRARY_UPDATED_EVENT, refreshLibrary);
    return () => {
      window.removeEventListener("focus", refreshLibrary);
      window.removeEventListener(SITE_SETTINGS_UPDATED_EVENT, refreshLibrary);
      window.removeEventListener(COMPONENT_LIBRARY_UPDATED_EVENT, refreshLibrary);
    };
  }, [loadComponents]);

  useEffect(() => {
    if (isNew) {
      setTitle("");
      setSlug("");
      setStatus("draft");
      setShowFooter(true);
      setSections([]);
    }
  }, [isNew]);

  // Mark load as complete and capture initial state so we don't auto-save on first paint
  useEffect(() => {
    if (isNew || !id || !page?.id) return;
    const numId = Number(id);
    if (Number.isNaN(numId) || loadCompleteForIdRef.current === numId) return;
    loadCompleteForIdRef.current = numId;
    const sectionsJson = JSON.stringify(sections.map((s) => ({ ...s, blocks: serializeSectionBlocks(s) })));
    lastSavedRef.current = { title, slug, status, sectionsJson, showFooter };
  }, [isNew, id, page?.id, title, slug, status, sections, showFooter]);

  // Auto-save when title, slug, status, showFooter, or sections change (debounced)
  useEffect(() => {
    if (isNew || !id || id === "new") return;
    const numId = Number(id);
    if (Number.isNaN(numId) || loadCompleteForIdRef.current !== numId) return;
    const sectionsJson = JSON.stringify(sections.map((s) => ({ ...s, blocks: serializeSectionBlocks(s) })));
    if (
      lastSavedRef.current &&
      lastSavedRef.current.title === title &&
      lastSavedRef.current.slug === slug &&
      lastSavedRef.current.status === status &&
      lastSavedRef.current.showFooter === showFooter &&
      lastSavedRef.current.sectionsJson === sectionsJson
    ) {
      return;
    }
    const t = window.setTimeout(async () => {
      setSaving(true);
      try {
        const effectiveStatus = status as "draft" | "published";
        const content = sections.map((s) => ({ ...s, blocks: serializeSectionBlocks(s) }));
        const settings = { showFooter };
        const payload = { title, slug: slugForApiPayload(slug), content, settings, status: effectiveStatus };
        await adminApi.put(adminEndpoints.page(numId), payload);
        setPage((p) => (p ? { ...p, title, slug, content: sections, settings, status: effectiveStatus } : null));
        setStatus(effectiveStatus);
        const nextJson = JSON.stringify(content);
        lastSavedRef.current = { title, slug, status: effectiveStatus, sectionsJson: nextJson, showFooter };
        showToast("Auto-saved.", "success");
      } catch (e) {
        showToast(e instanceof Error ? e.message : "Auto-save failed", "error");
      } finally {
        setSaving(false);
      }
    }, 1800);
    return () => window.clearTimeout(t);
  }, [id, isNew, title, slug, status, sections, showFooter]);

  useEffect(() => {
    const targetIndex = pendingScrollSectionIndexRef.current;
    if (targetIndex === null) return;
    pendingScrollSectionIndexRef.current = null;
    const timer = window.setTimeout(() => {
      document
        .querySelector(`[data-editor-section-index="${targetIndex}"]`)
        ?.scrollIntoView({ behavior: "smooth", block: "center" });
    }, 80);
    return () => window.clearTimeout(timer);
  }, [sections]);

  const updateBlock = (sectionIndex: number, blockIndex: number, content: Record<string, unknown>) => {
    const contentCopy = JSON.parse(JSON.stringify(content)) as Record<string, unknown>;
    setSections((prev) => {
      const next = prev.map((s, si) =>
        si !== sectionIndex ? s : { ...s, blocks: s.blocks.map((b, bi) => (bi !== blockIndex ? b : { ...b, content: contentCopy })) }
      );
      return next;
    });
    setBlockPreviewRevision((prev) => {
      const key = `${sectionIndex}:${blockIndex}`;
      return { ...prev, [key]: (prev[key] ?? 0) + 1 };
    });
  };

  const removeBlock = (sectionIndex: number, blockIndex: number) => {
    setSections((prev) =>
      prev.map((s, i) =>
        i !== sectionIndex ? s : { ...s, blocks: s.blocks.filter((_, bi) => bi !== blockIndex) }
      )
    );
  };

  const copyBlockToClipboard = (sectionIndex: number, blockIndex: number) => {
    const block = sections[sectionIndex]?.blocks[blockIndex];
    if (!block || block == null) return;
    const payload = {
      componentId: block.componentId,
      componentName: block.componentName,
      componentSlug: block.componentSlug ?? getBlockSlug(block),
      content: block.content ?? {},
    };
    copyTextToClipboard(JSON.stringify(payload)).then(
      () => showToast("Block copied. Paste on another page or section.", "success"),
      () => showToast("Could not copy to clipboard.", "error")
    );
  };

  const updateSection = (sectionIndex: number, patch: { width?: PageSection["width"]; style?: SectionStyleSettings; id?: string }) => {
    setSections((prev) =>
      prev.map((s, i) =>
        i !== sectionIndex
          ? s
          : {
              ...s,
              ...(patch.width !== undefined ? { width: patch.width } : {}),
              ...(patch.style !== undefined ? { style: patch.style } : {}),
              ...(patch.id !== undefined ? { id: patch.id } : {}),
            }
      )
    );
  };

  const addSection = (width: "full" | "container", layout: PageSection["layout"], insertIndex?: number) => {
    const insertAt = insertIndex ?? sectionInsertIndex;
    const clampedIndex = Math.min(Math.max(0, insertAt), sections.length);
    const newSection: SectionWithSlots = {
      width,
      layout,
      blocks: [],
      id: `section-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
      style: normalizeSectionStyle({}),
    };

    setSections((prev) => {
      const next = [...prev];
      const index = Math.min(Math.max(0, insertAt), next.length);
      next.splice(index, 0, newSection);
      return next;
    });
    setSectionModalOpen(false);
    pendingScrollSectionIndexRef.current = clampedIndex;

    if (components.length > 0) {
      setComponentPickerTarget({ sectionIndex: clampedIndex });
    } else {
      showToast("Section added. Add components to the library to fill it.", "info");
    }
  };

  const openSectionModalAt = (insertIndex: number) => {
    setSectionInsertIndex(Math.max(0, insertIndex));
    setSectionWidth("container");
    setSectionLayout("100");
    setSectionModalOpen(true);
  };

  const removeSection = (sectionIndex: number) => {
    setSections((prev) => prev.filter((_, i) => i !== sectionIndex));
  };

  const moveSection = (sectionIndex: number, dir: -1 | 1) => {
    const newIndex = sectionIndex + dir;
    if (newIndex < 0 || newIndex >= sections.length) return;
    setSections((prev) => {
      const next = [...prev];
      [next[sectionIndex], next[newIndex]] = [next[newIndex], next[sectionIndex]];
      return next;
    });
  };

  /** Apply placement using latest section state; only updates React state when placement succeeds. */
  const commitPageBlockPlacement = (
    block: PageBlock,
    options: {
      sectionIndex?: number;
      slotIndex?: number;
      allowNewSection?: boolean;
    },
  ): BlockInsertResult => {
    const result = placePageBlock(sectionsRef.current, block, options);
    if (result.ok) {
      setSections(result.nextSections);
    }
    return result;
  };

  const openPasteJsonModal = (
    sectionIndex?: number,
    slotIndex?: number,
    options?: { initialText?: string; initialError?: string; initialStep?: "paste" | "preview" }
  ) => {
    setPasteError("");
    setManualPasteTarget({ sectionIndex, slotIndex });
    setPasteModalInitial({
      text: options?.initialText ?? "",
      error: options?.initialError ?? "",
      step: options?.initialStep ?? "paste",
    });
    setManualPasteOpen(true);
  };

  const closePasteJsonModal = () => {
    setManualPasteOpen(false);
    setManualPasteTarget(null);
    setPasteModalInitial({ text: "", error: "", step: "paste" });
  };

  const applyPastedComponentJson = (
    text: string,
    sectionIndex?: number,
    slotIndex?: number,
    options?: { errorTarget?: "inline" | "modal" }
  ): { ok: true } | { ok: false; error: string } => {
    const errorTarget = options?.errorTarget ?? "inline";
    const currentSections = sectionsRef.current;

    pasteDebug("insert:start", {
      textLength: text.length,
      sectionIndex,
      slotIndex,
      sectionsCount: currentSections.length,
      componentsCount: componentsRef.current.length,
      secureContext: typeof window !== "undefined" ? window.isSecureContext : null,
      clipboardReadAvailable: isClipboardReadAvailable(),
    });

    if (errorTarget === "inline") {
      setPasteError("");
    }

    try {
      const result = parsePastedComponentJson(text, componentsRef.current);
      if (result.ok === false) {
        if (errorTarget === "inline") setPasteError(result.error);
        showToast(result.error, "error");
        pasteDebug("insert:validation-failed", result.error);
        return { ok: false, error: result.error };
      }

      const { block, warnings } = result;

      const insertResult = commitPageBlockPlacement(block, {
        sectionIndex,
        slotIndex,
        allowNewSection: sectionIndex === undefined,
      });

      if (insertResult.ok === false) {
        const message = blockInsertFailureMessage(insertResult.reason, "paste");
        if (errorTarget === "inline") setPasteError(message);
        showToast(message, "error");
        pasteDebug("insert:placement-failed", insertResult);
        return { ok: false, error: message };
      }

      if (insertResult.staleSectionRedirect) {
        pasteDebug("insert:stale-section-index", {
          requested: sectionIndex,
          sectionsCount: currentSections.length,
        });
        showToast("Target section changed — placing in the nearest available section.", "info");
      } else if (insertResult.staleSlotRedirect) {
        pasteDebug("insert:stale-slot-index", { sectionIndex, slotIndex });
        showToast("Target slot was filled — placed in the next available slot.", "info");
      }
      if (insertResult.mode === "new-section") {
        showToast("Section was full — added a new section for the pasted component.", "info");
      }

      for (const warning of warnings) {
        showToast(warning, "info");
      }
      showToast(`"${block.componentName}" inserted. Preview updated.`, "success");
      pasteDebug("insert:success", { mode: insertResult.mode, componentName: block.componentName });
      return { ok: true };
    } catch (e) {
      const message = e instanceof Error ? e.message : "An unexpected error occurred while inserting the component.";
      if (errorTarget === "inline") setPasteError(message);
      showToast(message, "error");
      pasteLogError("insert:unexpected-error", e);
      return { ok: false, error: message };
    }
  };

  const pasteFromClipboard = async (sectionIndex?: number, slotIndex?: number) => {
    setPasteError("");
    pasteDebug("clipboard:read-start", { sectionIndex, slotIndex, available: isClipboardReadAvailable() });

    try {
      let text: string;
      try {
        text = await readTextFromClipboard();
      } catch (e) {
        pasteLogError("clipboard:read-failed", e);
        const message =
          e instanceof Error && e.message
            ? e.message
            : "Clipboard read is unavailable. Use Paste JSON and paste manually.";
        setPasteError(message);
        showToast(message, "info");
        openPasteJsonModal(sectionIndex, slotIndex);
        return;
      }

      pasteDebug("clipboard:read-success", { length: text.length });

      if (!normalizePastedText(text)) {
        const message = PASTE_COMPONENT_CLIPBOARD_EMPTY_ERROR;
        setPasteError(message);
        showToast(message, "error");
        openPasteJsonModal(sectionIndex, slotIndex);
        return;
      }

      const preview = parsePastedComponentJson(text, componentsRef.current);
      if (preview.ok === false) {
        setPasteError(preview.error);
        showToast(preview.error, "error");
        openPasteJsonModal(sectionIndex, slotIndex, {
          initialText: text,
          initialError: preview.error,
          initialStep: "paste",
        });
        return;
      }

      openPasteJsonModal(sectionIndex, slotIndex, {
        initialText: text,
        initialStep: "preview",
      });
    } catch (e) {
      pasteLogError("clipboard:unexpected-error", e);
      const message = "Could not read clipboard. Use Paste JSON to paste manually.";
      setPasteError(message);
      showToast(message, "error");
      openPasteJsonModal(sectionIndex, slotIndex);
    }
  };

  const buildBlockFromComponent = (c: ComponentRecord): PageBlock => ({
    instanceId: createPageBlockInstanceId(),
    componentId: c.id,
    componentName: c.name,
    componentSlug: c.slug,
    content: cloneBlockContent(c.content ?? {}, c.slug),
  });

  const findPageBlockLocation = (
    list: SectionWithSlots[],
    target: { id: number; slug: string },
  ): { sectionIndex: number; blockIndex: number } | null => {
    for (let sectionIndex = 0; sectionIndex < list.length; sectionIndex += 1) {
      const section = list[sectionIndex];
      for (let blockIndex = 0; blockIndex < section.blocks.length; blockIndex += 1) {
        const block = section.blocks[blockIndex];
        if (!block) continue;
        const blockSlug = resolveBlockSlug(block, componentsRef.current);
        if (block.componentId === target.id || blockSlug === target.slug) {
          return { sectionIndex, blockIndex };
        }
      }
    }
    return null;
  };

  /** Link Competition Navigation to an existing page block, or add the library component once. */
  const ensureCompetitionTargetOnPage = (target: {
    id: number;
    name: string;
    slug: string;
  }): { status: "created" | "linked"; sectionIndex: number; blockIndex: number } | null => {
    const existing = findPageBlockLocation(sectionsRef.current, target);
    if (existing) {
      showToast("Component already exists on this page. Linked successfully.", "success");
      return { status: "linked", ...existing };
    }

    const library = componentsRef.current.find((component) => (
      component.id === target.id || component.slug === target.slug
    ));
    if (!library) {
      showToast("Could not find that component in the library.", "error");
      return null;
    }

    const block = buildBlockFromComponent(library);
    const insertResult = commitPageBlockPlacement(block, { allowNewSection: true });
    if (insertResult.ok === false) {
      showToast(blockInsertFailureMessage(insertResult.reason, "library"), "error");
      return null;
    }

    const location = findPageBlockLocation(insertResult.nextSections, {
      id: library.id,
      slug: library.slug,
    });
    if (!location) {
      showToast(`"${library.name}" was added, but its page position could not be found.`, "error");
      return null;
    }

    pendingScrollSectionIndexRef.current = location.sectionIndex;
    setCollapsedSections((prev) => {
      if (!prev.has(location.sectionIndex)) return prev;
      const next = new Set(prev);
      next.delete(location.sectionIndex);
      return next;
    });

    if (insertResult.mode === "new-section" || insertResult.mode === "first-section") {
      showToast(`"${library.name}" added in a new section.`, "success");
    } else {
      showToast(`"${library.name}" added to the page.`, "success");
    }

    return { status: "created", ...location };
  };

  const addComponentFromPicker = (c: ComponentRecord, target: ComponentPickerTarget | null) => {
    const block = buildBlockFromComponent(c);

    const insertResult = commitPageBlockPlacement(block, {
      sectionIndex: target?.sectionIndex,
      slotIndex: target?.slotIndex,
      allowNewSection: target?.sectionIndex === undefined,
    });

    if (insertResult.ok === false) {
      showToast(blockInsertFailureMessage(insertResult.reason, "library"), "error");
      return;
    }

    if (insertResult.staleSectionRedirect) {
      showToast("Target section changed — placed in the nearest available section.", "info");
    } else if (insertResult.staleSlotRedirect) {
      showToast("Target slot was filled — placed in the next available slot.", "info");
    }
    if (insertResult.mode === "new-section") {
      showToast("Section was full — added a new section for the component.", "info");
    }

    showToast(`"${c.name}" added to the page from the component library.`, "success");
  };

  const openComponentPicker = (target: ComponentPickerTarget = {}) => {
    setComponentPickerTarget(target);
  };

  const savePage = async (nextStatus?: "draft" | "published") => {
    setSaving(true);
    try {
      const effectiveStatus = nextStatus ?? status;
      const content = sections.map((s) => ({
        ...s,
        blocks: serializeSectionBlocks(s),
      }));
      const settings = { showFooter };
      const payload = { title, slug: slugForApiPayload(slug), content, settings, status: effectiveStatus };
      if (isNew) {
        const data = await adminApi.post<{ page: PageRecord }>(adminEndpoints.pages, payload);
        navigate(`/dashboard/pages/${data.page.id}/edit`, { replace: true });
      } else {
        await adminApi.put(adminEndpoints.page(Number(id)), payload);
        setPage((p) => (p ? { ...p, title, slug, content: sections, settings, status: effectiveStatus } : null));
        const sectionsJson = JSON.stringify(content);
        lastSavedRef.current = { title, slug, status: effectiveStatus, sectionsJson, showFooter };
      }
      setStatus(effectiveStatus);
      showToast(effectiveStatus === "published" ? "Page published." : "Draft saved.", "success");
    } catch (e) {
      showToast(e instanceof Error ? e.message : "Save failed", "error");
    } finally {
      setSaving(false);
    }
  };

  if (!isNew && loadError) {
    return (
      <div className="page-editor-root">
        <header className="page-editor-header">
          <button type="button" onClick={() => navigate("/dashboard/pages")} style={{ display: "inline-flex", alignItems: "center", gap: 6, border: "none", background: "transparent", cursor: "pointer", fontWeight: 500 }}>
            <ArrowLeft size={18} /> Pages
          </button>
        </header>
        <main className="page-editor-main">
          <p style={{ color: "#b91c1c" }}>{loadError}</p>
        </main>
      </div>
    );
  }

  return (
    <div className="page-editor-root">
      <header className="page-editor-header">
        <button
          type="button"
          onClick={() => navigate("/dashboard/pages")}
          style={{
            display: "inline-flex",
            alignItems: "center",
            gap: 6,
            border: "none",
            background: "transparent",
            cursor: "pointer",
            color: "#0f172a",
            fontWeight: 500,
          }}
        >
          <ArrowLeft size={18} />
          Pages
        </button>
        <div className="page-editor-header-actions">
          <button
            type="button"
            onClick={() => savePage("draft")}
            disabled={saving}
            style={{
              minWidth: 96,
              padding: "8px 14px",
              borderRadius: 999,
              border: "1px solid #e2e8f0",
              background: status === "draft" ? "#e5e7eb" : "#ffffff",
              color: "#0f172a",
              fontWeight: 500,
              fontSize: 13,
              cursor: saving ? "not-allowed" : "pointer",
            }}
          >
            {saving && status === "draft" ? "Saving..." : "Draft"}
          </button>
          <button
            type="button"
            onClick={() => savePage("published")}
            disabled={saving}
            style={{
              minWidth: 96,
              padding: "8px 14px",
              borderRadius: 999,
              border: "none",
              background: "#0f172a",
              color: "#ffffff",
              fontWeight: 600,
              fontSize: 13,
              cursor: saving ? "not-allowed" : "pointer",
            }}
          >
            {saving && status === "published" ? "Saving..." : isNew ? "Publish" : "Update"}
          </button>
          <button
            type="button"
            onClick={() => {
              if (!slug.trim()) {
                showToast("Please set a slug before previewing.", "info");
                return;
              }
              const path = status === "published"
                ? (isHomepageSlug(slug) ? "/" : `/${normalizePageSlug(slug)}`)
                : (isHomepageSlug(slug) ? "/preview" : `/preview/${normalizePageSlug(slug)}`);
              window.open(path, "_blank", "noopener,noreferrer");
            }}
            style={{
              minWidth: 96,
              padding: "8px 14px",
              borderRadius: 999,
              border: "1px solid #e2e8f0",
              background: "#ffffff",
              color: "#0f172a",
              fontWeight: 500,
              fontSize: 13,
              cursor: "pointer",
            }}
          >
            Preview
          </button>
        </div>
      </header>
      {toast && (
        <div
          style={{
            position: "fixed",
            top: 72,
            right: 24,
            zIndex: 40,
            maxWidth: 320,
          }}
        >
          <div
            style={{
              padding: "10px 14px",
              borderRadius: 10,
              fontSize: 13,
              fontWeight: 500,
              background:
                toast.type === "success"
                  ? "#ecfdf3"
                  : toast.type === "info"
                  ? "#eff6ff"
                  : "#fef2f2",
              color:
                toast.type === "success"
                  ? "#166534"
                  : toast.type === "info"
                  ? "#1d4ed8"
                  : "#b91c1c",
              border:
                toast.type === "success"
                  ? "1px solid #bbf7d0"
                  : toast.type === "info"
                  ? "1px solid #bfdbfe"
                  : "1px solid #fecaca",
              boxShadow: "0 10px 25px rgba(15,23,42,0.25)",
            }}
          >
            {toast.message}
          </div>
        </div>
      )}
      <main className="page-editor-main">
        <div className="page-editor-form-card">
          <h1 style={{ margin: "0 0 20px", fontSize: 22, fontWeight: 700, color: "#0f172a" }}>{isNew ? "New page" : "Edit page"}</h1>
          <div className="page-editor-form-row">
            <div className="page-editor-form-field">
              <label style={{ display: "block", marginBottom: 8, fontWeight: 500, fontSize: 14, color: "#374151" }}>Title</label>
              <input
                type="text"
                value={title}
                onChange={(e) => setTitle(e.target.value)}
                required
                style={{ width: "100%", padding: "12px 14px", border: "1px solid #e5e7eb", borderRadius: 10, boxSizing: "border-box", fontSize: 15, outline: "none" }}
              />
            </div>
            <div className="page-editor-form-field">
              <label style={{ display: "block", marginBottom: 8, fontWeight: 500, fontSize: 14, color: "#374151" }}>Slug</label>
              <input
                type="text"
                value={slug}
                onChange={(e) => setSlug(e.target.value)}
                placeholder="/ for homepage, or test, services/web-development"
                style={{ width: "100%", padding: "12px 14px", border: "1px solid #e5e7eb", borderRadius: 10, boxSizing: "border-box", fontSize: 15, outline: "none" }}
              />
            </div>
            <div className="page-editor-form-field page-editor-form-field--status">
              <label style={{ display: "block", marginBottom: 8, fontWeight: 500, fontSize: 14, color: "#374151" }}>Status</label>
              <select
                value={status}
                onChange={(e) => setStatus(e.target.value)}
                style={{ padding: "12px 14px", border: "1px solid #e5e7eb", borderRadius: 10, minWidth: 140, fontSize: 15, background: "#fff", cursor: "pointer" }}
              >
                <option value="draft">Draft</option>
                <option value="published">Published</option>
              </select>
            </div>
          </div>
          <div className="page-editor-form-row" style={{ marginTop: 16 }}>
            <div className="page-editor-form-field" style={{ flex: "1 1 100%" }}>
              <label style={{ display: "inline-flex", alignItems: "center", gap: 8, fontSize: 14, color: "#374151", cursor: "pointer", fontWeight: 500 }}>
                <input
                  type="checkbox"
                  checked={showFooter}
                  onChange={(e) => setShowFooter(e.target.checked)}
                />
                Show Default Footer
              </label>
              <p style={{ margin: "8px 0 0", fontSize: 12, color: "#64748b" }}>
                When enabled, the site default footer is shown. Turn off to hide the footer on this page.
              </p>
            </div>
          </div>
        </div>

        <div style={{ marginBottom: 20 }}>
          <div className="page-editor-section-toolbar">
            <span style={{ fontWeight: 600, fontSize: 16, color: "#0f172a" }}>Sections & components</span>
            <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
              <button
                type="button"
                onClick={() => openSectionModalAt(sections.length)}
                style={{
                  display: "inline-flex",
                  alignItems: "center",
                  gap: 8,
                  padding: "10px 18px",
                  background: "linear-gradient(180deg, #0f172a 0%, #1e293b 100%)",
                  color: "#fff",
                  border: "none",
                  borderRadius: 10,
                  cursor: "pointer",
                  fontWeight: 600,
                  fontSize: 14,
                  boxShadow: "0 2px 8px rgba(15,23,42,0.25)",
                }}
              >
                <Plus size={18} /> Add section
              </button>
            </div>
          </div>
          <div className="page-editor-add-section-row">
            <button
              type="button"
              onClick={() => pasteFromClipboard()}
              title="Read component JSON from clipboard and open preview before inserting"
              style={{ padding: "9px 16px", background: "#f8fafc", border: "1px solid #e2e8f0", borderRadius: 10, cursor: "pointer", fontWeight: 500, fontSize: 14 }}
            >
              Paste from clipboard
            </button>
            <button
              type="button"
              onClick={() => openPasteJsonModal()}
              title="Paste or type component JSON manually"
              style={{ padding: "9px 16px", background: "#f8fafc", border: "1px solid #e2e8f0", borderRadius: 10, cursor: "pointer", fontWeight: 500, fontSize: 14 }}
            >
              Paste JSON
            </button>
            <button
              type="button"
              onClick={() => openComponentPicker()}
              disabled={components.length === 0}
              style={{
                display: "inline-flex",
                alignItems: "center",
                gap: 8,
                padding: "9px 16px",
                background: components.length === 0 ? "#cbd5e1" : "#0f172a",
                color: "#fff",
                border: "none",
                borderRadius: 10,
                cursor: components.length === 0 ? "not-allowed" : "pointer",
                fontWeight: 500,
                fontSize: 14,
              }}
            >
              <Plus size={16} /> Add component
            </button>
          </div>
          {pasteError && <p style={{ color: "#b91c1c", margin: "0 0 8px", fontSize: 14 }}>{pasteError}</p>}
          <p style={{ margin: "0 0 12px", fontSize: 12, color: "#64748b", lineHeight: 1.5 }}>
            Paste component JSON copied from the Component Library. You will review a preview before it is added to the page.
            Plain text, emojis, and other clipboard content are not supported.
          </p>
        </div>

        <p style={{ margin: "0 0 12px", fontSize: 12, color: "#64748b" }}>
          Page preview below uses the current Site Settings header{hasPageFooter ? "" : " and footer"} layouts.
        </p>

        <SiteChromeFrame
          key={siteChromeKey}
          previewMode
          showGlobalFooter={!hasPageFooter}
          className="page-editor-site-preview rounded-2xl overflow-hidden border border-slate-200 shadow-sm mb-8"
        >
        {sections.length === 0 ? (
          <div style={{ background: "#fff", padding: 48, borderRadius: 16, textAlign: "center", color: "#64748b", boxShadow: "0 1px 3px rgba(0,0,0,0.06)" }}>
            <p style={{ margin: "0 0 8px", fontSize: 16 }}>No sections yet.</p>
            <p style={{ margin: "0 0 16px", fontSize: 14 }}>Add a section, then choose a component to place inside it.</p>
            <button type="button" onClick={() => openSectionModalAt(0)} style={{ padding: "12px 24px", background: "#0f172a", color: "#fff", border: "none", borderRadius: 10, cursor: "pointer", fontWeight: 600 }}>
              Add first section
            </button>
          </div>
        ) : (
          <div className="page-editor-sections-stack">
            <SectionInsertDivider onClick={() => openSectionModalAt(0)} label="Add section at top" />
            {sections.map((section, si) => (
              <Fragment key={section.id ?? `section-${si}`}>
              <div
                data-editor-section-index={si}
                style={{
                  background: "#fff",
                  borderRadius: 16,
                  boxShadow: "0 1px 3px rgba(0,0,0,0.06)",
                  overflow: "hidden",
                  border: "1px solid #e5e7eb",
                }}
              >
                <div className="page-editor-section-row" style={{ borderBottom: collapsedSections.has(si) ? "none" : "1px solid #e5e7eb" }}>
                  <div className="page-editor-section-row-label">
                    <button type="button" onClick={() => toggleSectionCollapsed(si)} title={collapsedSections.has(si) ? "Expand section" : "Collapse section"} style={{ padding: 4, border: "none", background: "none", cursor: "pointer", color: "#64748b", display: "flex", alignItems: "center", justifyContent: "center" }}>
                      {collapsedSections.has(si) ? <ChevronRight size={20} /> : <ChevronDown size={20} />}
                    </button>
                    <span style={{ fontSize: 13, color: "#64748b" }}>
                      {section.width === "full" ? "Full width" : "Container"} · {SECTION_LAYOUTS.find((l) => l.id === section.layout)?.label ?? section.layout}
                      {collapsedSections.has(si) && <span style={{ marginLeft: 6, color: "#94a3b8", fontWeight: 500 }}>(collapsed)</span>}
                    </span>
                  </div>
                  <div className="page-editor-section-row-actions">
                    <button type="button" onClick={() => moveSection(si, -1)} disabled={si === 0} title="Move section up" style={{ padding: 6, border: "none", background: "none", cursor: si === 0 ? "not-allowed" : "pointer", color: si === 0 ? "#cbd5e1" : "#64748b" }}><ChevronUp size={18} /></button>
                    <button type="button" onClick={() => moveSection(si, 1)} disabled={si === sections.length - 1} title="Move section down" style={{ padding: 6, border: "none", background: "none", cursor: si === sections.length - 1 ? "not-allowed" : "pointer", color: si === sections.length - 1 ? "#cbd5e1" : "#64748b" }}><ChevronDown size={18} /></button>
                    <button
                      type="button"
                      onClick={() => setEditingSectionIndex(si)}
                      title="Edit section styling"
                      style={{ display: "inline-flex", alignItems: "center", gap: 6, padding: "6px 12px", background: "#0f172a", color: "#fff", border: "none", borderRadius: 8, cursor: "pointer", fontSize: 13, fontWeight: 500 }}
                    >
                      <Settings2 size={14} /> Edit section
                    </button>
                    <button type="button" onClick={() => pasteFromClipboard(si)} title="Paste component JSON from clipboard into this section" style={{ padding: "6px 12px", fontSize: 13, background: "#f1f5f9", border: "none", borderRadius: 8, cursor: "pointer" }}>Paste</button>
                    <button
                      type="button"
                      onClick={() => openComponentPicker({ sectionIndex: si })}
                      disabled={components.length === 0}
                      style={{
                        display: "inline-flex",
                        alignItems: "center",
                        gap: 6,
                        padding: "6px 12px",
                        fontSize: 13,
                        background: "#0f172a",
                        color: "#fff",
                        border: "none",
                        borderRadius: 8,
                        cursor: components.length === 0 ? "not-allowed" : "pointer",
                        fontWeight: 500,
                        opacity: components.length === 0 ? 0.6 : 1,
                      }}
                    >
                      <Plus size={14} /> Add component
                    </button>
                    <button type="button" onClick={() => removeSection(si)} style={{ padding: 6, color: "#b91c1c", border: "none", background: "none", cursor: "pointer" }}><Trash2 size={18} /></button>
                  </div>
                </div>
                {!collapsedSections.has(si) && (
                <PageSectionRenderer
                  as="div"
                  section={{
                    width: section.width,
                    layout: section.layout,
                    blocks: section.blocks.filter((b): b is PageBlock => b != null),
                    id: section.id,
                    style: section.style,
                  }}
                  sectionIndex={si}
                  gridTemplateColumns={`repeat(${getColumnCount(section.layout)}, 1fr)`}
                  gridClassName="page-editor-section-slots"
                  editorPreviewBreakpoint={sectionPreviewBp[si]}
                >
                  {Array.from({ length: getColumnCount(section.layout) }, (_, slotIndex) => {
                    const block = section.blocks[slotIndex];
                    if (block) {
                      return (
                        <div key={block.instanceId ?? `${si}-${slotIndex}-${block.componentId}-${block.componentSlug ?? getBlockSlug(block)}`} className="page-editor-slot">
                          <div className="page-editor-block-toolbar">
                            <span style={{ fontSize: 13, fontWeight: 500, color: "#374151" }}>{block.componentName}</span>
                            <div className="page-editor-block-toolbar-actions">
                              <button type="button" onClick={() => copyBlockToClipboard(si, slotIndex)} title="Copy block to paste on another page" style={{ display: "inline-flex", alignItems: "center", gap: 6, padding: "6px 10px", background: "#f1f5f9", border: "none", borderRadius: 8, cursor: "pointer", fontSize: 13, fontWeight: 500 }}><Copy size={14} /> Copy</button>
                              <button type="button" onClick={() => setEditingBlock({ sectionIndex: si, blockIndex: slotIndex })} style={{ display: "inline-flex", alignItems: "center", gap: 6, padding: "6px 12px", background: "#0f172a", color: "#fff", border: "none", borderRadius: 8, cursor: "pointer", fontSize: 13, fontWeight: 500 }}><Pencil size={14} /> Edit</button>
                              <button type="button" onClick={() => removeBlock(si, slotIndex)} style={{ padding: 4, color: "#b91c1c", border: "none", background: "none", cursor: "pointer" }}><Trash2 size={18} /></button>
                            </div>
                          </div>
                          <div style={{ padding: 12, maxHeight: 560, overflow: "auto" }}>
                            {(() => {
                              const blockSlug = getBlockSlug(block);
                              if (!shouldRenderFooterBlock(blockSlug, pageSettings)) {
                                return (
                                  <span className="text-muted-foreground text-sm italic">
                                    Hidden by Page Settings (Show Default Footer is off)
                                  </span>
                                );
                              }
                              const BlockComp = getBlockComponent(blockSlug);
                              if (!BlockComp) return <span className="text-muted-foreground text-sm italic">No preview</span>;
                              const previewRevision = blockPreviewRevision[`${si}:${slotIndex}`] ?? 0;
                              const rawContent = block.content ?? {};
                              const libraryContent = findComponentLibraryContent(block, components, blockSlug);
                              const previewContent = resolveEditorBlockContent(rawContent, {
                                blockSlug,
                                libraryContent,
                                pageVars: placeholderVars,
                              });
                              // Editor always renders competition components normally.
                              // Only the Grade Hero preview keeps its nav bar interactive.
                              const isGradeHero = blockSlug === "grade-hero" || blockSlug === "design-to-impact-hero";
                              if (isGradeHero && competitionNavState.hasCompetitionNavigation) {
                                return (
                                  <GradeHeroBlock
                                    key={`block-preview-${block.instanceId ?? `${si}-${slotIndex}`}-${previewRevision}-${siteChromeKey}`}
                                    content={previewContent}
                                    activeCompetitionNavId={activeCompetitionNavId}
                                    onCompetitionNavClick={handleCompetitionNavClick}
                                  />
                                );
                              }
                              return (
                                <BlockComp
                                  key={`block-preview-${block.instanceId ?? `${si}-${slotIndex}`}-${previewRevision}-${siteChromeKey}`}
                                  content={previewContent}
                                />
                              );
                            })()}
                          </div>
                        </div>
                      );
                    }
                    return (
                      <div
                        key={slotIndex}
                        style={{
                          padding: 24,
                          textAlign: "center",
                          color: "#94a3b8",
                          fontSize: 14,
                          background: "#f8fafc",
                          borderRadius: 12,
                          border: "1px dashed #e2e8f0",
                          display: "flex",
                          flexDirection: "column",
                          alignItems: "center",
                          justifyContent: "center",
                          gap: 10,
                          minHeight: 120,
                        }}
                      >
                        <span>Slot {slotIndex + 1}</span>
                        <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", justifyContent: "center" }}>
                          <button type="button" onClick={() => pasteFromClipboard(si, slotIndex)} title="Paste component JSON from clipboard into this slot" style={{ padding: "6px 12px", fontSize: 13, background: "#f1f5f9", border: "none", borderRadius: 8, cursor: "pointer" }}>Paste</button>
                          <button
                            type="button"
                            onClick={() => openComponentPicker({ sectionIndex: si, slotIndex })}
                            disabled={components.length === 0}
                            style={{
                              display: "inline-flex",
                              alignItems: "center",
                              gap: 6,
                              padding: "6px 12px",
                              fontSize: 13,
                              background: "#0f172a",
                              color: "#fff",
                              border: "none",
                              borderRadius: 8,
                              cursor: components.length === 0 ? "not-allowed" : "pointer",
                              fontWeight: 500,
                              opacity: components.length === 0 ? 0.6 : 1,
                            }}
                          >
                            <Plus size={14} /> Add component
                          </button>
                        </div>
                      </div>
                    );
                  })}
                </PageSectionRenderer>
                )}
              </div>
              <SectionInsertDivider onClick={() => openSectionModalAt(si + 1)} />
              </Fragment>
            ))}
          </div>
        )}
        </SiteChromeFrame>
      </main>

      {sections.length > 0 && (
        <div className="page-editor-fab" role="toolbar" aria-label="Quick page actions">
          <button
            type="button"
            className="page-editor-fab-btn"
            onClick={() => openSectionModalAt(sections.length)}
            title="Add section at bottom"
          >
            <Plus size={20} aria-hidden />
            Add section
          </button>
        </div>
      )}

      {editingSectionIndex !== null && sections[editingSectionIndex] && (
        <SectionStyleEditForm
          sectionIndex={editingSectionIndex}
          section={{
            width: sections[editingSectionIndex].width,
            layout: sections[editingSectionIndex].layout,
            blocks: sections[editingSectionIndex].blocks.filter((b): b is PageBlock => b != null),
            id: sections[editingSectionIndex].id,
            style: sections[editingSectionIndex].style,
          }}
          onChange={(patch) => updateSection(editingSectionIndex, patch)}
          onPreviewBreakpointChange={(bp) =>
            setSectionPreviewBp((prev) => ({ ...prev, [editingSectionIndex]: bp }))
          }
          initialPreviewBreakpoint={sectionPreviewBp[editingSectionIndex] ?? "desktop"}
          onSave={() => {
            setEditingSectionIndex(null);
            showToast("Section styling updated.", "success");
          }}
          onClose={() => setEditingSectionIndex(null)}
        />
      )}

      {editingBlock !== null && (() => {
        const sec = sections[editingBlock.sectionIndex];
        const block = sec?.blocks[editingBlock.blockIndex];
        if (!block) return null;
        const blockSlug = getBlockSlug(block);
        const libraryContent = findComponentLibraryContent(block, components, blockSlug);
        return (
          <BlockEditForm
            componentName={block.componentName}
            blockSlug={blockSlug}
            initialContent={(block.content ?? {}) as Record<string, unknown>}
            libraryContent={libraryContent}
            placeholderVars={placeholderVars}
            siteChromeKey={siteChromeKey}
            showGlobalFooter={blockSlug !== "footer" && blockSlug !== "pbel-guide-footer"}
            onSave={(content) => {
              updateBlock(editingBlock.sectionIndex, editingBlock.blockIndex, content);
              setEditingBlock(null);
              showToast("Content updated.", "success");
            }}
            onClose={() => setEditingBlock(null)}
            onError={(msg) => showToast(msg, "error")}
            onEnsurePageComponent={
              blockSlug === "grade-hero" || blockSlug === "design-to-impact-hero"
                ? ensureCompetitionTargetOnPage
                : undefined
            }
            onApplyAndOpenBlock={
              blockSlug === "grade-hero" || blockSlug === "design-to-impact-hero"
                ? (nextContent, location) => {
                    updateBlock(editingBlock.sectionIndex, editingBlock.blockIndex, nextContent);
                    setEditingBlock({
                      sectionIndex: location.sectionIndex,
                      blockIndex: location.blockIndex,
                    });
                  }
                : undefined
            }
          />
        );
      })()}

      {sectionModalOpen && (
        <div
          style={{
            position: "fixed",
            inset: 0,
            zIndex: 50,
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            background: "rgba(0,0,0,0.4)",
            padding: 24,
          }}
        >
          <div
            style={{
              background: "#fff",
              borderRadius: 20,
              boxShadow: "0 24px 48px rgba(0,0,0,0.15)",
              maxWidth: 520,
              width: "100%",
              maxHeight: "90vh",
              overflow: "auto",
            }}
          >
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "20px 24px", borderBottom: "1px solid #e5e7eb" }}>
              <h2 style={{ margin: 0, fontSize: 18, fontWeight: 700, color: "#0f172a" }}>Section Configuration</h2>
              <button type="button" onClick={() => setSectionModalOpen(false)} style={{ padding: 8, border: "none", background: "none", cursor: "pointer", color: "#64748b" }}><X size={20} /></button>
            </div>
            <div style={{ padding: 24 }}>
              <p style={{ margin: "0 0 12px", fontWeight: 600, fontSize: 14, color: "#374151" }}>Section width</p>
              <div style={{ display: "flex", gap: 12, marginBottom: 24 }}>
                {(["full", "container"] as const).map((w) => (
                  <button
                    key={w}
                    type="button"
                    onClick={() => setSectionWidth(w)}
                    style={{
                      flex: 1,
                      padding: "14px",
                      borderRadius: 12,
                      border: sectionWidth === w ? "2px solid #0f172a" : "1px solid #e5e7eb",
                      background: sectionWidth === w ? "#f1f5f9" : "#fff",
                      cursor: "pointer",
                      fontWeight: 600,
                      fontSize: 14,
                      textTransform: "capitalize",
                    }}
                  >
                    {w === "full" ? "Full width" : "Container width"}
                  </button>
                ))}
              </div>
              <p style={{ margin: "0 0 12px", fontWeight: 600, fontSize: 14, color: "#374151" }}>Column layout</p>
              <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(140px, 1fr))", gap: 10 }}>
                {SECTION_LAYOUTS.map((opt) => (
                  <button
                    key={opt.id}
                    type="button"
                    onClick={() => setSectionLayout(opt.id)}
                    style={{
                      padding: "14px 12px",
                      borderRadius: 12,
                      border: sectionLayout === opt.id ? "2px solid #0f172a" : "1px solid #e5e7eb",
                      background: sectionLayout === opt.id ? "#f1f5f9" : "#fff",
                      cursor: "pointer",
                      fontSize: 12,
                      textAlign: "center",
                      display: "flex",
                      flexDirection: "column",
                      alignItems: "center",
                      gap: 6,
                    }}
                  >
                    <div style={{ display: "flex", gap: 2, width: "100%", justifyContent: "center" }}>
                      {opt.columns.map((pct, i) => (
                        <div key={i} style={{ width: `${pct}%`, maxWidth: 24, height: 20, background: sectionLayout === opt.id ? "#0f172a" : "#94a3b8", borderRadius: 4 }} />
                      ))}
                    </div>
                    <span style={{ fontWeight: 500 }}>{opt.label}</span>
                  </button>
                ))}
              </div>
            </div>
            <div style={{ padding: "16px 24px", borderTop: "1px solid #e5e7eb", display: "flex", justifyContent: "flex-end", gap: 12 }}>
              <button type="button" onClick={() => setSectionModalOpen(false)} style={{ padding: "10px 20px", background: "#f1f5f9", border: "none", borderRadius: 10, cursor: "pointer", fontWeight: 500 }}>Cancel</button>
              <button type="button" onClick={() => addSection(sectionWidth, sectionLayout)} style={{ padding: "10px 20px", background: "#0f172a", color: "#fff", border: "none", borderRadius: 10, cursor: "pointer", fontWeight: 600 }}>Continue</button>
            </div>
          </div>
        </div>
      )}

      {componentPickerTarget !== null && (
        <ComponentPickerModal
          components={components}
          target={componentPickerTarget}
          onSelect={addComponentFromPicker}
          onClose={() => setComponentPickerTarget(null)}
        />
      )}

      {manualPasteOpen && (
        <PasteComponentJsonModal
          open={manualPasteOpen}
          components={components}
          placeholderVars={placeholderVars}
          siteChromeKey={siteChromeKey}
          showGlobalFooter={!hasPageFooter}
          target={manualPasteTarget}
          initialText={pasteModalInitial.text}
          initialError={pasteModalInitial.error}
          initialStep={pasteModalInitial.step}
          onClose={closePasteJsonModal}
          onApply={(text) => {
            const result = applyPastedComponentJson(
              text,
              manualPasteTarget?.sectionIndex,
              manualPasteTarget?.slotIndex,
              { errorTarget: "modal" },
            );
            if ("error" in result) return { error: result.error };
            return true;
          }}
        />
      )}
    </div>
  );
}
