"use client";

/**
 * Final-review chip modal: **Core values** and **method** facets share the
 * kebab → **Duplicate** (values only when under the cap) / **Remove** pattern
 * from the create-card facet modals (`Create` +
 * {@link buildCustomRuleModalKebabMenu}), plus a footer **Remove** when the
 * chip is already in the selection. Values and method chips also offer
 * **Customize**, which opens {@link CustomMethodCardWizard} prefilled from the
 * chip. Fields are editable on open; Save persists body edits without renaming.
 *
 * Template-only chips without an `overrideKey` never mount this component; they
 * use {@link TemplateChipDetailModal} from the parent.
 *
 * @see CommunicationMethodsScreen — mental model for method modals.
 */

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import Create from "../../../components/modals/Create";
import ContentLockup from "../../../components/type/ContentLockup";
import { useMessages, useTranslation } from "../../../contexts/MessagesContext";
import {
  CommunicationMethodEditFields,
  ConflictManagementEditFields,
  CoreValueEditFields,
  DecisionApproachEditFields,
  MembershipMethodEditFields,
} from "./methodEditFields";
import CustomMethodCardModalBody from "./CustomMethodCardModalBody";
import { buildCustomRuleModalKebabMenu } from "./customRuleModalKebabMenu";
import { useDiscardCustomizeConfirm } from "../hooks/useDiscardCustomizeConfirm";
import { useBeforeUnloadGuard } from "../../../hooks/useBeforeUnloadGuard";
import {
  communicationPresetFor,
  conflictManagementPresetFor,
  coreValuePresetFor,
  decisionApproachPresetFor,
  membershipPresetFor,
} from "../../../../lib/create/finalReviewChipPresets";
import { isCustomMethodCardId } from "../../../../lib/create/isCustomMethodCardId";
import { usesWizardFieldBlocksModalBody } from "../../../../lib/create/usesWizardFieldBlocksModalBody";
import type { CustomMethodCardFieldBlock } from "../../../../lib/create/customMethodCardFieldBlocks";
import {
  CUSTOM_RULE_FACET_BY_GROUP,
  isCatalogMethodCardId,
  type TemplateFacetGroupKey,
} from "../../../../lib/create/customRuleFacets";
import type { MethodFacetGroupKey } from "../../../../lib/create/removeMethodCardFromFacetSelection";
import { removeMethodCardFromFacetSelection } from "../../../../lib/create/removeMethodCardFromFacetSelection";
import { mergePresetMethodsWithCustom } from "../../../../lib/create/mergePresetMethodsWithCustom";
import { moveFacetSelectionIdToFront } from "../../../../lib/create/methodCardSelectionOrder";
import {
  buildMethodCardWizardInitialValues,
  coreValueDetailsFromWizardFieldBlocks,
  overlayFacetPrefillValues,
} from "../../../../lib/create/methodCardWizardPrefill";
import type {
  MethodCardWizardFacetPrefill,
  MethodCardWizardInitialValues,
} from "../../../../lib/create/methodCardWizardPrefill";
import { uploadCreateFlowFile } from "../../../../lib/create/uploadToServer";
import CustomMethodCardWizard from "./CustomMethodCardWizard";
import {
  duplicateCoreValueChipInDraft,
  removeCoreValueChipFromDraft,
} from "../../../../lib/create/coreValueChipFacet";
import {
  captureMethodCardCustomizeSnapshot,
  isMethodCardCustomizeSessionDirty,
  type MethodCardCustomizeSnapshot,
  type MethodCardHeaderDraft,
} from "../../../../lib/create/methodCardCustomizeSession";
import type {
  CommunicationMethodDetailEntry,
  ConflictManagementDetailEntry,
  CoreValueDetailEntry,
  CreateFlowState,
  DecisionApproachDetailEntry,
  MembershipMethodDetailEntry,
} from "../types";

export type FinalReviewChipEditTarget = {
  /** Stable key for override lookup: preset id (methods) or chip id (core values). */
  overrideKey: string;
  /** Category group that decides which field set to render. */
  groupKey: TemplateFacetGroupKey;
  /** Display label shown at the top of the modal (localized chip label). */
  chipLabel: string;
};

export type FinalReviewChipEditPatch =
  | {
      groupKey: "coreValues";
      overrideKey: string;
      value: CoreValueDetailEntry;
      /** When set, updates the display label for this chip id in `coreValuesChipsSnapshot`. */
      chipLabel?: string;
      customMethodCardFieldBlocks?: CustomMethodCardFieldBlock[];
    }
  | {
      groupKey: "communication";
      overrideKey: string;
      value: CommunicationMethodDetailEntry;
      customMethodCardFieldBlocks?: CustomMethodCardFieldBlock[];
      methodCardMeta?: { label: string; supportText: string };
    }
  | {
      groupKey: "membership";
      overrideKey: string;
      value: MembershipMethodDetailEntry;
      customMethodCardFieldBlocks?: CustomMethodCardFieldBlock[];
      methodCardMeta?: { label: string; supportText: string };
    }
  | {
      groupKey: "decisionApproaches";
      overrideKey: string;
      value: DecisionApproachDetailEntry;
      customMethodCardFieldBlocks?: CustomMethodCardFieldBlock[];
      methodCardMeta?: { label: string; supportText: string };
    }
  | {
      groupKey: "conflictManagement";
      overrideKey: string;
      value: ConflictManagementDetailEntry;
      customMethodCardFieldBlocks?: CustomMethodCardFieldBlock[];
      methodCardMeta?: { label: string; supportText: string };
    };

export interface FinalReviewChipEditModalProps {
  isOpen: boolean;
  onClose: () => void;
  target: FinalReviewChipEditTarget | null;
  state: CreateFlowState;
  onSave: (_patch: FinalReviewChipEditPatch) => void;
  replaceState: (_updater: (prev: CreateFlowState) => CreateFlowState) => void;
  onInteract?: () => void;
  /** After core-value **Duplicate**, re-point the open modal at the new chip id. */
  onEditTargetChange?: (_next: FinalReviewChipEditTarget) => void;
}

type Draft =
  | { groupKey: "coreValues"; value: CoreValueDetailEntry }
  | { groupKey: "communication"; value: CommunicationMethodDetailEntry }
  | { groupKey: "membership"; value: MembershipMethodDetailEntry }
  | { groupKey: "decisionApproaches"; value: DecisionApproachDetailEntry }
  | { groupKey: "conflictManagement"; value: ConflictManagementDetailEntry };

type MethodDetailDraft =
  | CommunicationMethodDetailEntry
  | MembershipMethodDetailEntry
  | DecisionApproachDetailEntry
  | ConflictManagementDetailEntry;

function methodDetailDraftForCustomizeSession(
  draft: Draft | null,
): MethodDetailDraft | null {
  if (!draft || draft.groupKey === "coreValues") return null;
  return draft.value;
}

function isMethodFacetGroup(
  k: TemplateFacetGroupKey,
): k is MethodFacetGroupKey {
  return k !== "coreValues";
}

export function FinalReviewChipEditModal({
  isOpen,
  onClose,
  target,
  state,
  onSave,
  replaceState,
  onInteract,
  onEditTargetChange,
}: FinalReviewChipEditModalProps) {
  const m = useMessages();
  const cr = m.create.customRule;
  const tCv = cr.coreValues;
  const tComm = cr.communication;
  const tMem = cr.membership;
  const tDa = cr.decisionApproaches;
  const tCm = cr.conflictManagement;
  const modalKebabMenu = cr.modalKebabMenu;
  const tModal = useTranslation(
    "create.reviewAndComplete.finalReview.chipEditModal",
  );
  const { confirmDiscard, confirmDialog } = useDiscardCustomizeConfirm();

  const [draft, setDraft] = useState<Draft | null>(null);
  const [draftFieldBlocks, setDraftFieldBlocks] = useState<
    CustomMethodCardFieldBlock[] | null
  >(null);
  const [customizeHeaderDraft, setCustomizeHeaderDraft] =
    useState<MethodCardHeaderDraft | null>(null);
  const [addCustomWizardOpen, setAddCustomWizardOpen] = useState(false);
  const [wizardCustomizeCardId, setWizardCustomizeCardId] = useState<
    string | null
  >(null);
  const [wizardInitialValues, setWizardInitialValues] =
    useState<MethodCardWizardInitialValues | null>(null);

  const initialSnapshotRef = useRef("");
  const seededTargetRef = useRef<string | null>(null);
  const customizeSnapshotRef = useRef<
    | MethodCardCustomizeSnapshot<
        | CommunicationMethodDetailEntry
        | MembershipMethodDetailEntry
        | DecisionApproachDetailEntry
        | ConflictManagementDetailEntry
      >
    | null
  >(null);
  const coreCustomizeSnapshotRef =
    useRef<MethodCardCustomizeSnapshot<CoreValueDetailEntry> | null>(null);
  const pendingEphemeralCoreDuplicateRef = useRef<string | null>(null);
  const methodById = useMemo(() => {
    if (!target || !isMethodFacetGroup(target.groupKey)) {
      return new Map<string, { id: string; label: string; supportText: string }>();
    }
    const facet = CUSTOM_RULE_FACET_BY_GROUP.get(target.groupKey)!;
    const selectedIds = facet.selectionIds(state);
    switch (target.groupKey) {
      case "communication":
        return new Map(
          mergePresetMethodsWithCustom(
            tComm.methods,
            selectedIds,
            state.customMethodCardMetaById,
          ).map((row) => [row.id, row]),
        );
      case "membership":
        return new Map(
          mergePresetMethodsWithCustom(
            tMem.methods,
            selectedIds,
            state.customMethodCardMetaById,
          ).map((row) => [row.id, row]),
        );
      case "decisionApproaches":
        return new Map(
          mergePresetMethodsWithCustom(
            tDa.methods,
            selectedIds,
            state.customMethodCardMetaById,
          ).map((row) => [row.id, row]),
        );
      case "conflictManagement":
        return new Map(
          mergePresetMethodsWithCustom(
            tCm.methods,
            selectedIds,
            state.customMethodCardMetaById,
          ).map((row) => [row.id, row]),
        );
    }
  }, [
    target,
    state.customMethodCardMetaById,
    state.selectedCommunicationMethodIds,
    state.selectedMembershipMethodIds,
    state.selectedDecisionApproachIds,
    state.selectedConflictManagementIds,
    tComm.methods,
    tMem.methods,
    tDa.methods,
    tCm.methods,
  ]);

  const selectionIdsForTarget = useMemo(() => {
    if (!target || !isMethodFacetGroup(target.groupKey)) return [];
    return [...CUSTOM_RULE_FACET_BY_GROUP.get(target.groupKey)!.selectionIds(state)];
  }, [
    target,
    state.selectedCommunicationMethodIds,
    state.selectedMembershipMethodIds,
    state.selectedDecisionApproachIds,
    state.selectedConflictManagementIds,
  ]);

  const isChipInSelection =
    target && isMethodFacetGroup(target.groupKey)
      ? selectionIdsForTarget.includes(target.overrideKey)
      : false;

  useEffect(() => {
    if (!isOpen || !target) return;
    const sig = facetSeedSignature(target, state);
    const targetKey = `${target.groupKey}:${target.overrideKey}:${sig}`;
    if (seededTargetRef.current === targetKey) {
      return;
    }

    const seed = seedDraftForTarget(target, state);
    setDraft(seed);
    initialSnapshotRef.current = JSON.stringify(seed.value);
    if (target.groupKey === "coreValues") {
      const persisted =
        state.customMethodCardFieldBlocksById?.[target.overrideKey];
      const initialBlocks =
        Array.isArray(persisted) && persisted.length > 0
          ? structuredClone(persisted)
          : null;
      const headerDraft: MethodCardHeaderDraft = {
        title: target.chipLabel,
        description: "",
      };
      setCustomizeHeaderDraft(headerDraft);
      coreCustomizeSnapshotRef.current = captureMethodCardCustomizeSnapshot(
        seed.value as CoreValueDetailEntry,
        initialBlocks,
        headerDraft,
      );
      setDraftFieldBlocks(initialBlocks);
    }
    if (isMethodFacetGroup(target.groupKey) && seed.groupKey !== "coreValues") {
      const persisted =
        state.customMethodCardFieldBlocksById?.[target.overrideKey];
      const initialBlocks =
        Array.isArray(persisted) && persisted.length > 0
          ? structuredClone(persisted)
          : isCustomMethodCardId(
              target.overrideKey,
              state.customMethodCardMetaById,
            )
            ? structuredClone(persisted ?? [])
            : null;
      const method = methodById.get(target.overrideKey);
      const meta = state.customMethodCardMetaById?.[target.overrideKey];
      const headerDraft: MethodCardHeaderDraft = {
        title: meta?.label ?? method?.label ?? target.chipLabel,
        description: meta?.supportText ?? method?.supportText ?? "",
      };
      setCustomizeHeaderDraft(headerDraft);
      customizeSnapshotRef.current = captureMethodCardCustomizeSnapshot(
        seed.value as MethodDetailDraft,
        initialBlocks,
        headerDraft,
      );
      setDraftFieldBlocks(initialBlocks);
    }
    seededTargetRef.current = targetKey;
  }, [isOpen, target, state, methodById]);

  useEffect(() => {
    if (!isOpen) seededTargetRef.current = null;
  }, [isOpen]);

  const coreCustomizeSaveDisabled = useMemo(() => {
    const snap = coreCustomizeSnapshotRef.current;
    if (!snap || !draft || draft.groupKey !== "coreValues") return true;
    return !isMethodCardCustomizeSessionDirty(
      snap,
      draft.value,
      draftFieldBlocks,
      customizeHeaderDraft,
    );
  }, [customizeHeaderDraft, draft, draftFieldBlocks]);

  const methodCustomizeSaveDisabled = useMemo(() => {
    const snap = customizeSnapshotRef.current;
    if (!snap) return true;
    return !isMethodCardCustomizeSessionDirty(
      snap,
      methodDetailDraftForCustomizeSession(draft),
      draftFieldBlocks,
      customizeHeaderDraft,
    );
  }, [
    customizeHeaderDraft,
    draft,
    draftFieldBlocks,
  ]);

  useBeforeUnloadGuard(
    isOpen &&
      !addCustomWizardOpen &&
      (!coreCustomizeSaveDisabled || !methodCustomizeSaveDisabled),
  );

  const modalUsesWizardFieldBlocksBody = Boolean(
    target &&
      (usesWizardFieldBlocksModalBody({
        methodId: target.overrideKey,
        meta: state.customMethodCardMetaById,
        fieldBlocksById: state.customMethodCardFieldBlocksById,
        modalEditUnlocked: true,
        draftFieldBlocks,
      }) ||
        (isCustomMethodCardId(
          target.overrideKey,
          state.customMethodCardMetaById,
        ) &&
          !isCatalogMethodCardId(target.overrideKey))),
  );

  const handleWizardFieldBlocksChange = useCallback(
    (next: CustomMethodCardFieldBlock[]) => {
      setDraftFieldBlocks(next);
      setDraft((prev) => {
        if (!prev || prev.groupKey !== "coreValues") {
          return prev;
        }
        return {
          groupKey: "coreValues",
          value: coreValueDetailsFromWizardFieldBlocks(next, prev.value),
        };
      });
    },
    [],
  );

  const finalizeModalClose = useCallback(() => {
    customizeSnapshotRef.current = null;
    coreCustomizeSnapshotRef.current = null;
    pendingEphemeralCoreDuplicateRef.current = null;
    setDraftFieldBlocks(null);
    setCustomizeHeaderDraft(null);
    setAddCustomWizardOpen(false);
    setWizardCustomizeCardId(null);
    setWizardInitialValues(null);
    onClose();
  }, [onClose]);

  const handleModalClose = useCallback(async () => {
    if (
      target &&
      target.groupKey === "coreValues" &&
      !(await confirmDiscard(
        true,
        coreCustomizeSnapshotRef.current,
        draft?.groupKey === "coreValues" ? draft.value : null,
        draftFieldBlocks,
        customizeHeaderDraft,
      ))
    ) {
      return;
    }
    if (
      target &&
      isMethodFacetGroup(target.groupKey) &&
      !(await confirmDiscard(
        true,
        customizeSnapshotRef.current,
        methodDetailDraftForCustomizeSession(draft),
        draftFieldBlocks,
        customizeHeaderDraft,
      ))
    ) {
      return;
    }
    const ep = pendingEphemeralCoreDuplicateRef.current;
    if (ep) {
      replaceState((prev) => ({
        ...prev,
        ...removeCoreValueChipFromDraft(prev, ep),
      }));
    }
    finalizeModalClose();
  }, [
    confirmDiscard,
    customizeHeaderDraft,
    draft,
    draftFieldBlocks,
    finalizeModalClose,
    replaceState,
    target,
  ]);

  const handleCustomize = useCallback(() => {
    onInteract?.();
    if (!target) {
      return;
    }
    if (target.groupKey === "coreValues") {
      const value =
        draft?.groupKey === "coreValues"
          ? draft.value
          : coreValuePresetFor(target.overrideKey);
      setWizardInitialValues(
        buildMethodCardWizardInitialValues({
          cardId: target.overrideKey,
          fallbackTitle: target.chipLabel,
          fallbackDescription:
            value.supportText?.trim() || tCv.detailModal.subtitle,
          meta: {},
          persistedBlocks: state.customMethodCardFieldBlocksById,
          draftFieldBlocks: null,
          facetPrefill: {
            group: "coreValues",
            draft: value,
            headings: {
              meaning: tCv.detailModal.meaningLabel,
              signals: tCv.detailModal.signalsLabel,
            },
          },
        }),
      );
      setWizardCustomizeCardId(target.overrideKey);
      setAddCustomWizardOpen(true);
      return;
    }
    if (!isMethodFacetGroup(target.groupKey)) {
      return;
    }
    const method = methodById.get(target.overrideKey);
    const meta = state.customMethodCardMetaById?.[target.overrideKey];
    let facetPrefill: MethodCardWizardFacetPrefill | undefined;
    if (draft && draft.groupKey === "communication") {
      facetPrefill = {
        group: "communication",
        draft: draft.value,
        headings: tComm.sectionHeadings,
      };
    } else if (draft && draft.groupKey === "membership") {
      facetPrefill = {
        group: "membership",
        draft: draft.value,
        headings: tMem.sectionHeadings,
      };
    } else if (draft && draft.groupKey === "decisionApproaches") {
      facetPrefill = {
        group: "decisionApproaches",
        draft: draft.value,
        headings: tDa.sectionHeadings,
      };
    } else if (draft && draft.groupKey === "conflictManagement") {
      facetPrefill = {
        group: "conflictManagement",
        draft: draft.value,
        headings: tCm.sectionHeadings,
      };
    }
    setWizardInitialValues(
      buildMethodCardWizardInitialValues({
        cardId: target.overrideKey,
        fallbackTitle: method?.label ?? target.chipLabel,
        fallbackDescription: method?.supportText ?? meta?.supportText ?? "",
        meta: state.customMethodCardMetaById,
        persistedBlocks: state.customMethodCardFieldBlocksById,
        draftFieldBlocks,
        facetPrefill,
      }),
    );
    setWizardCustomizeCardId(target.overrideKey);
    setAddCustomWizardOpen(true);
  }, [
    draft,
    draftFieldBlocks,
    methodById,
    onInteract,
    state.customMethodCardFieldBlocksById,
    state.customMethodCardMetaById,
    tCm.sectionHeadings,
    tComm.sectionHeadings,
    tCv.detailModal.meaningLabel,
    tCv.detailModal.signalsLabel,
    tCv.detailModal.subtitle,
    tDa.sectionHeadings,
    tMem.sectionHeadings,
    target,
  ]);

  const handleRemoveSelectedFromModal = useCallback(async () => {
    if (!target || !isMethodFacetGroup(target.groupKey)) {
      return;
    }
    const methodGroupKey = target.groupKey;
    if (!selectionIdsForTarget.includes(target.overrideKey)) {
      return;
    }
    onInteract?.();
    if (
      !(await confirmDiscard(
        true,
        customizeSnapshotRef.current,
        methodDetailDraftForCustomizeSession(draft),
        draftFieldBlocks,
        customizeHeaderDraft,
      ))
    ) {
      return;
    }
    customizeSnapshotRef.current = null;
    replaceState((prev) => ({
      ...prev,
      ...removeMethodCardFromFacetSelection(
        prev,
        methodGroupKey,
        target.overrideKey,
      ),
    }));
    finalizeModalClose();
  }, [
    confirmDiscard,
    customizeHeaderDraft,
    draft,
    draftFieldBlocks,
    finalizeModalClose,
    onInteract,
    replaceState,
    selectionIdsForTarget,
    target,
  ]);

  const handleRemoveCoreValueFromModal = useCallback(async () => {
    if (!target || target.groupKey !== "coreValues") {
      return;
    }
    onInteract?.();
    if (
      !(await confirmDiscard(
        true,
        coreCustomizeSnapshotRef.current,
        draft?.groupKey === "coreValues" ? draft.value : null,
        draftFieldBlocks,
        customizeHeaderDraft,
      ))
    ) {
      return;
    }
    coreCustomizeSnapshotRef.current = null;
    customizeSnapshotRef.current = null;
    replaceState((prev) => ({
      ...prev,
      ...removeCoreValueChipFromDraft(prev, target.overrideKey),
    }));
    finalizeModalClose();
  }, [
    confirmDiscard,
    customizeHeaderDraft,
    draft,
    draftFieldBlocks,
    finalizeModalClose,
    onInteract,
    replaceState,
    target,
  ]);

  const handleDuplicateCoreValue = useCallback(async () => {
    if (
      !target ||
      target.groupKey !== "coreValues" ||
      draft?.groupKey !== "coreValues"
    ) {
      return;
    }
    if ((state.editingPublishedRuleId?.trim() ?? "") !== "") {
      return;
    }
    if ((state.selectedCoreValueIds ?? []).length >= 5) {
      return;
    }
    if (
      !(await confirmDiscard(
        true,
        coreCustomizeSnapshotRef.current,
        draft.value,
        draftFieldBlocks,
        customizeHeaderDraft,
      ))
    ) {
      return;
    }
    onInteract?.();
    const priorEphemeral = pendingEphemeralCoreDuplicateRef.current;
    let outcome: ReturnType<
      typeof duplicateCoreValueChipInDraft
    > | null = null;
    replaceState((prev) => {
      const base =
        priorEphemeral != null
          ? { ...prev, ...removeCoreValueChipFromDraft(prev, priorEphemeral) }
          : prev;
      const res = duplicateCoreValueChipInDraft(
        base,
        target.overrideKey,
        modalKebabMenu.duplicateTitleSuffix,
      );
      if (!res) {
        return prev;
      }
      outcome = res;
      return { ...base, ...res.patch };
    });
    if (!outcome) {
      return;
    }
    customizeSnapshotRef.current = null;
    coreCustomizeSnapshotRef.current = null;
    setDraftFieldBlocks(null);
    setCustomizeHeaderDraft(null);
    pendingEphemeralCoreDuplicateRef.current = outcome.newId;
    seededTargetRef.current = null;
    setDraft({
      groupKey: "coreValues",
      value: structuredClone(draft.value),
    });
    onEditTargetChange?.({
      overrideKey: outcome.newId,
      groupKey: "coreValues",
      chipLabel: outcome.newLabel,
    });
  }, [
    confirmDiscard,
    customizeHeaderDraft,
    draft,
    draftFieldBlocks,
    modalKebabMenu.duplicateTitleSuffix,
    onEditTargetChange,
    onInteract,
    replaceState,
    state.editingPublishedRuleId,
    state.selectedCoreValueIds,
    target,
  ]);

  const kebabMenuItems = useMemo(() => {
    if (!target) return [];
    if (target.groupKey === "coreValues") {
      return buildCustomRuleModalKebabMenu(modalKebabMenu, {
        showCustomize: true,
        onCustomize: handleCustomize,
        onDuplicate:
          (state.editingPublishedRuleId?.trim() ?? "") !== "" ||
          (state.selectedCoreValueIds ?? []).length >= 5
            ? undefined
            : handleDuplicateCoreValue,
        showRemove: true,
        onRemove: handleRemoveCoreValueFromModal,
      });
    }
    if (!isMethodFacetGroup(target.groupKey)) return [];
    return buildCustomRuleModalKebabMenu(modalKebabMenu, {
      showCustomize: true,
      onCustomize: handleCustomize,
      showRemove: isChipInSelection,
      onRemove: handleRemoveSelectedFromModal,
    });
  }, [
    handleCustomize,
    handleDuplicateCoreValue,
    handleRemoveCoreValueFromModal,
    handleRemoveSelectedFromModal,
    isChipInSelection,
    modalKebabMenu,
    state.editingPublishedRuleId,
    state.selectedCoreValueIds,
    target,
  ]);

  const subtitle = useMemo(() => {
    if (!target) return "";
    return subtitleForTarget(
      target,
      { tCv, tComm, tMem, tDa, tCm },
      state.customMethodCardMetaById,
      state.coreValueDetailsByChipId?.[target.overrideKey]?.supportText,
    );
  }, [
    target,
    tCv,
    tComm,
    tMem,
    tDa,
    tCm,
    state.customMethodCardMetaById,
    state.coreValueDetailsByChipId,
  ]);

  const handleCoreSave = useCallback(() => {
    if (!target || !draft || draft.groupKey !== "coreValues") {
      return;
    }
    if (coreCustomizeSaveDisabled) {
      return;
    }
    onInteract?.();
    const existingBlocks =
      state.customMethodCardFieldBlocksById?.[target.overrideKey];
    onSave({
      groupKey: "coreValues",
      overrideKey: target.overrideKey,
      value: structuredClone(draft.value),
      ...(existingBlocks && existingBlocks.length > 0
        ? {
            customMethodCardFieldBlocks: overlayFacetPrefillValues(
              existingBlocks,
              {
                group: "coreValues",
                draft: draft.value,
                headings: {
                  meaning: tCv.detailModal.meaningLabel,
                  signals: tCv.detailModal.signalsLabel,
                },
              },
            ),
          }
        : {}),
    });
    coreCustomizeSnapshotRef.current = captureMethodCardCustomizeSnapshot(
      draft.value,
      draftFieldBlocks,
      customizeHeaderDraft ?? {
        title: target.chipLabel,
        description: "",
      },
    );
    initialSnapshotRef.current = JSON.stringify(draft.value);
    pendingEphemeralCoreDuplicateRef.current = null;
  }, [
    coreCustomizeSaveDisabled,
    customizeHeaderDraft,
    draft,
    draftFieldBlocks,
    onInteract,
    onSave,
    state.customMethodCardFieldBlocksById,
    tCv.detailModal.meaningLabel,
    tCv.detailModal.signalsLabel,
    target,
  ]);

  const handleMethodPrimary = useCallback(() => {
    if (!target || !draft || !isMethodFacetGroup(target.groupKey)) return;
    if (!isMethodFacetGroup(draft.groupKey)) return;
    const facet = CUSTOM_RULE_FACET_BY_GROUP.get(target.groupKey)!;
    const pendingId = target.overrideKey;
    const sel = [...facet.selectionIds(state)];
    onInteract?.();

    const persistWizardBlocks = draftFieldBlocks !== null;
    const blocksPayload = persistWizardBlocks
      ? structuredClone(draftFieldBlocks ?? [])
      : undefined;

    switch (draft.groupKey) {
      case "communication":
        onSave({
          groupKey: "communication",
          overrideKey: pendingId,
          value: draft.value,
          ...(blocksPayload !== undefined
            ? { customMethodCardFieldBlocks: blocksPayload }
            : {}),
        });
        break;
      case "membership":
        onSave({
          groupKey: "membership",
          overrideKey: pendingId,
          value: draft.value,
          ...(blocksPayload !== undefined
            ? { customMethodCardFieldBlocks: blocksPayload }
            : {}),
        });
        break;
      case "decisionApproaches":
        onSave({
          groupKey: "decisionApproaches",
          overrideKey: pendingId,
          value: draft.value,
          ...(blocksPayload !== undefined
            ? { customMethodCardFieldBlocks: blocksPayload }
            : {}),
        });
        break;
      case "conflictManagement":
        onSave({
          groupKey: "conflictManagement",
          overrideKey: pendingId,
          value: draft.value,
          ...(blocksPayload !== undefined
            ? { customMethodCardFieldBlocks: blocksPayload }
            : {}),
        });
        break;
    }

    if (!sel.includes(pendingId)) {
      replaceState((prev) => ({
        ...prev,
        [facet.selectedIdsStateKey]: moveFacetSelectionIdToFront(
          [...facet.selectionIds(prev)],
          pendingId,
        ),
      }));
      finalizeModalClose();
      return;
    }

    const sessionDraft = methodDetailDraftForCustomizeSession(draft);
    if (sessionDraft) {
      customizeSnapshotRef.current = captureMethodCardCustomizeSnapshot(
        sessionDraft,
        draftFieldBlocks,
        customizeHeaderDraft ?? { title: "", description: "" },
      );
    }
  }, [
    customizeHeaderDraft,
    draft,
    draftFieldBlocks,
    finalizeModalClose,
    onInteract,
    onSave,
    replaceState,
    state,
    target,
  ]);

  const handleCloseAddWizard = useCallback(() => {
    setAddCustomWizardOpen(false);
    setWizardCustomizeCardId(null);
    setWizardInitialValues(null);
  }, []);

  const handleFinalizeCustomCard = useCallback(
    ({
      title,
      description,
      fieldBlocks,
    }: {
      title: string;
      description: string;
      fieldBlocks: CustomMethodCardFieldBlock[];
    }) => {
      if (!target || !draft) {
        return;
      }
      if (target.groupKey === "coreValues" && draft.groupKey === "coreValues") {
        const existingId = wizardCustomizeCardId ?? target.overrideKey;
        onInteract?.();
        const details = coreValueDetailsFromWizardFieldBlocks(
          fieldBlocks,
          draft.value,
        );
        const trimmedDescription = description.trim();
        onSave({
          groupKey: "coreValues",
          overrideKey: existingId,
          value: {
            ...details,
            ...(trimmedDescription.length > 0
              ? { supportText: trimmedDescription }
              : {}),
          },
          chipLabel: title,
          customMethodCardFieldBlocks: structuredClone(fieldBlocks),
        });
        setDraft({
          groupKey: "coreValues",
          value: {
            ...details,
            ...(trimmedDescription.length > 0
              ? { supportText: trimmedDescription }
              : {}),
          },
        });
        setDraftFieldBlocks(structuredClone(fieldBlocks));
        coreCustomizeSnapshotRef.current = captureMethodCardCustomizeSnapshot(
          {
            ...details,
            ...(trimmedDescription.length > 0
              ? { supportText: trimmedDescription }
              : {}),
          },
          fieldBlocks,
          { title, description },
        );
        setAddCustomWizardOpen(false);
        setWizardCustomizeCardId(null);
        setWizardInitialValues(null);
        return;
      }
      if (
        !isMethodFacetGroup(target.groupKey) ||
        !isMethodFacetGroup(draft.groupKey)
      ) {
        return;
      }
      const existingId = wizardCustomizeCardId ?? target.overrideKey;
      onInteract?.();
      const meta = { label: title, supportText: description };
      const blocks = structuredClone(fieldBlocks);
      switch (draft.groupKey) {
        case "communication":
          onSave({
            groupKey: "communication",
            overrideKey: existingId,
            value: draft.value,
            methodCardMeta: meta,
            customMethodCardFieldBlocks: blocks,
          });
          break;
        case "membership":
          onSave({
            groupKey: "membership",
            overrideKey: existingId,
            value: draft.value,
            methodCardMeta: meta,
            customMethodCardFieldBlocks: blocks,
          });
          break;
        case "decisionApproaches":
          onSave({
            groupKey: "decisionApproaches",
            overrideKey: existingId,
            value: draft.value,
            methodCardMeta: meta,
            customMethodCardFieldBlocks: blocks,
          });
          break;
        case "conflictManagement":
          onSave({
            groupKey: "conflictManagement",
            overrideKey: existingId,
            value: draft.value,
            methodCardMeta: meta,
            customMethodCardFieldBlocks: blocks,
          });
          break;
      }
      customizeSnapshotRef.current = captureMethodCardCustomizeSnapshot(
        draft.value,
        blocks,
        { title, description },
      );
      setDraftFieldBlocks(blocks);
      setAddCustomWizardOpen(false);
      setWizardCustomizeCardId(null);
      setWizardInitialValues(null);
    },
    [
      draft,
      onInteract,
      onSave,
      target,
      wizardCustomizeCardId,
    ],
  );

  const handleNext = useCallback(() => {
    if (!target || !draft) return;
    if (target.groupKey === "coreValues") {
      handleCoreSave();
    } else {
      handleMethodPrimary();
    }
  }, [draft, handleCoreSave, handleMethodPrimary, target]);

  const nextButtonText = useMemo(() => {
    if (!target) return tModal("saveButton");
    if (target.groupKey === "coreValues") {
      return tModal("saveButton");
    }
    if (!isChipInSelection) {
      return addPrimaryLabelForMethodFacet(target.groupKey, cr);
    }
    return tModal("saveButton");
  }, [cr, isChipInSelection, target, tModal]);

  const headerContent = useMemo(() => {
    if (!target) return undefined;
    return (
      <div className="bg-[var(--color-surface-default-primary)] px-[24px] py-[12px] shrink-0">
        <ContentLockup
          title={target.chipLabel}
          description={subtitle}
          variant="modal"
          alignment="left"
        />
      </div>
    );
  }, [subtitle, target]);

  const showFooterRemove =
    target != null &&
    (target.groupKey === "coreValues" || isChipInSelection);

  return (
    <>
      <Create
      isOpen={isOpen && !addCustomWizardOpen}
      onClose={handleModalClose}
      onBack={handleModalClose}
      showBackButton={!showFooterRemove}
      showRemoveButton={showFooterRemove}
      onRemove={
        target?.groupKey === "coreValues"
          ? handleRemoveCoreValueFromModal
          : handleRemoveSelectedFromModal
      }
      backdropVariant="blurredYellow"
      headerContent={headerContent}
      showNextButton={true}
      onNext={handleNext}
      nextButtonText={nextButtonText}
      nextButtonDisabled={
        target?.groupKey === "coreValues"
          ? coreCustomizeSaveDisabled
          : methodCustomizeSaveDisabled
      }
      kebabTriggerAriaLabel={modalKebabMenu.triggerAriaLabel}
      kebabMenuAriaLabel={modalKebabMenu.menuAriaLabel}
      kebabMenuItems={
        target && kebabMenuItems.length > 0 ? kebabMenuItems : undefined
      }
      ariaLabel={target?.chipLabel || "Edit chip details"}
    >
      <div className="flex flex-col gap-[var(--measures-spacing-600,24px)] pb-2">
        {draft?.groupKey === "coreValues" &&
          target &&
          (modalUsesWizardFieldBlocksBody ? (
            <CustomMethodCardModalBody
              cardId={target.overrideKey}
              blocksById={state.customMethodCardFieldBlocksById}
              blocksOverride={
                draftFieldBlocks !== null ? draftFieldBlocks : undefined
              }
              showPolicyContentLockupWhenNoBlocks={false}
              onFieldBlocksChange={
                draftFieldBlocks === null
                  ? undefined
                  : handleWizardFieldBlocksChange
              }
            />
          ) : (
            <CoreValueEditFields
              value={draft.value}
              onChange={(value) => setDraft({ groupKey: "coreValues", value })}
            />
          ))}
        {draft?.groupKey === "communication" &&
          target &&
          (modalUsesWizardFieldBlocksBody ? (
            <CustomMethodCardModalBody
              cardId={target.overrideKey}
              blocksById={state.customMethodCardFieldBlocksById}
              blocksOverride={
                draftFieldBlocks !== null ? draftFieldBlocks : undefined
              }
              policyMeta={
                state.customMethodCardMetaById?.[target.overrideKey]
              }
              showPolicyContentLockupWhenNoBlocks={false}
              onFieldBlocksChange={
                draftFieldBlocks === null
                  ? undefined
                  : handleWizardFieldBlocksChange
              }
            />
          ) : (
            <CommunicationMethodEditFields
              value={draft.value}
              onChange={(value) =>
                setDraft({ groupKey: "communication", value })
              }
            />
          ))}
        {draft?.groupKey === "membership" &&
          target &&
          (modalUsesWizardFieldBlocksBody ? (
            <CustomMethodCardModalBody
              cardId={target.overrideKey}
              blocksById={state.customMethodCardFieldBlocksById}
              blocksOverride={
                draftFieldBlocks !== null ? draftFieldBlocks : undefined
              }
              policyMeta={
                state.customMethodCardMetaById?.[target.overrideKey]
              }
              showPolicyContentLockupWhenNoBlocks={false}
              onFieldBlocksChange={
                draftFieldBlocks === null
                  ? undefined
                  : handleWizardFieldBlocksChange
              }
            />
          ) : (
            <MembershipMethodEditFields
              value={draft.value}
              onChange={(value) =>
                setDraft({ groupKey: "membership", value })
              }
            />
          ))}
        {draft?.groupKey === "decisionApproaches" &&
          target &&
          (modalUsesWizardFieldBlocksBody ? (
            <CustomMethodCardModalBody
              cardId={target.overrideKey}
              blocksById={state.customMethodCardFieldBlocksById}
              blocksOverride={
                draftFieldBlocks !== null ? draftFieldBlocks : undefined
              }
              policyMeta={
                state.customMethodCardMetaById?.[target.overrideKey]
              }
              showPolicyContentLockupWhenNoBlocks={false}
              onFieldBlocksChange={
                draftFieldBlocks === null
                  ? undefined
                  : handleWizardFieldBlocksChange
              }
            />
          ) : (
            <DecisionApproachEditFields
              value={draft.value}
              onChange={(value) =>
                setDraft({ groupKey: "decisionApproaches", value })
              }
            />
          ))}
        {draft?.groupKey === "conflictManagement" &&
          target &&
          (modalUsesWizardFieldBlocksBody ? (
            <CustomMethodCardModalBody
              cardId={target.overrideKey}
              blocksById={state.customMethodCardFieldBlocksById}
              blocksOverride={
                draftFieldBlocks !== null ? draftFieldBlocks : undefined
              }
              policyMeta={
                state.customMethodCardMetaById?.[target.overrideKey]
              }
              showPolicyContentLockupWhenNoBlocks={false}
              onFieldBlocksChange={
                draftFieldBlocks === null
                  ? undefined
                  : handleWizardFieldBlocksChange
              }
            />
          ) : (
            <ConflictManagementEditFields
              value={draft.value}
              onChange={(value) =>
                setDraft({ groupKey: "conflictManagement", value })
              }
            />
          ))}
      </div>
    </Create>
    <CustomMethodCardWizard
      isOpen={addCustomWizardOpen}
      onClose={handleCloseAddWizard}
      initialValues={wizardInitialValues}
      onFinalize={handleFinalizeCustomCard}
      onPersistCustomUploadFile={(file) =>
        uploadCreateFlowFile(file, "customMethodAttachment")
      }
    />
    {confirmDialog}
    </>
  );
}

// ---------- helpers ------------------------------------------------------

function facetSeedSignature(
  target: FinalReviewChipEditTarget,
  state: CreateFlowState,
): string {
  const id = target.overrideKey;
  switch (target.groupKey) {
    case "coreValues":
      return JSON.stringify({
        details: state.coreValueDetailsByChipId?.[id],
        row:
          state.coreValuesChipsSnapshot?.find((r) => r.id === id) ?? null,
        blocks: state.customMethodCardFieldBlocksById?.[id] ?? null,
      });
    case "communication":
      return JSON.stringify({
        meta: state.customMethodCardMetaById?.[id] ?? null,
        details: state.communicationMethodDetailsById?.[id] ?? null,
        blocks: state.customMethodCardFieldBlocksById?.[id] ?? null,
      });
    case "membership":
      return JSON.stringify({
        meta: state.customMethodCardMetaById?.[id] ?? null,
        details: state.membershipMethodDetailsById?.[id] ?? null,
        blocks: state.customMethodCardFieldBlocksById?.[id] ?? null,
      });
    case "decisionApproaches":
      return JSON.stringify({
        meta: state.customMethodCardMetaById?.[id] ?? null,
        details: state.decisionApproachDetailsById?.[id] ?? null,
        blocks: state.customMethodCardFieldBlocksById?.[id] ?? null,
      });
    case "conflictManagement":
      return JSON.stringify({
        meta: state.customMethodCardMetaById?.[id] ?? null,
        details: state.conflictManagementDetailsById?.[id] ?? null,
        blocks: state.customMethodCardFieldBlocksById?.[id] ?? null,
      });
    default: {
      const _e: never = target.groupKey;
      return String(_e);
    }
  }
}

function addPrimaryLabelForMethodFacet(
  groupKey: MethodFacetGroupKey,
  cr: ReturnType<typeof useMessages>["create"]["customRule"],
): string {
  switch (groupKey) {
    case "communication":
      return cr.communication.addPlatform.nextButtonText;
    case "membership":
      return cr.membership.addPlatform.nextButtonText;
    case "decisionApproaches":
      return cr.decisionApproaches.addApproach.nextButtonText;
    case "conflictManagement":
      return cr.conflictManagement.addApproach.nextButtonText;
  }
}

function seedDraftForTarget(
  target: FinalReviewChipEditTarget,
  state: CreateFlowState,
): Draft {
  switch (target.groupKey) {
    case "coreValues": {
      const saved = state.coreValueDetailsByChipId?.[target.overrideKey];
      const preset = coreValuePresetFor(target.overrideKey);
      return {
        groupKey: "coreValues",
        value: {
          meaning: saved?.meaning ?? preset.meaning,
          signals: saved?.signals ?? preset.signals,
          ...(saved?.supportText ? { supportText: saved.supportText } : {}),
        },
      };
    }
    case "communication": {
      const saved =
        state.communicationMethodDetailsById?.[target.overrideKey] ??
        communicationPresetFor(target.overrideKey);
      return { groupKey: "communication", value: { ...saved } };
    }
    case "membership": {
      const saved =
        state.membershipMethodDetailsById?.[target.overrideKey] ??
        membershipPresetFor(target.overrideKey);
      return { groupKey: "membership", value: { ...saved } };
    }
    case "decisionApproaches": {
      const saved =
        state.decisionApproachDetailsById?.[target.overrideKey] ??
        decisionApproachPresetFor(target.overrideKey);
      return {
        groupKey: "decisionApproaches",
        value: {
          ...saved,
          applicableScope: [...saved.applicableScope],
          selectedApplicableScope: [...saved.selectedApplicableScope],
        },
      };
    }
    case "conflictManagement": {
      const saved =
        state.conflictManagementDetailsById?.[target.overrideKey] ??
        conflictManagementPresetFor(target.overrideKey);
      return {
        groupKey: "conflictManagement",
        value: {
          ...saved,
          applicableScope: [...saved.applicableScope],
          selectedApplicableScope: [...saved.selectedApplicableScope],
        },
      };
    }
  }
}

type SubtitleMessages = {
  tCv: ReturnType<typeof useMessages>["create"]["customRule"]["coreValues"];
  tComm: ReturnType<typeof useMessages>["create"]["customRule"]["communication"];
  tMem: ReturnType<typeof useMessages>["create"]["customRule"]["membership"];
  tDa: ReturnType<
    typeof useMessages
  >["create"]["customRule"]["decisionApproaches"];
  tCm: ReturnType<
    typeof useMessages
  >["create"]["customRule"]["conflictManagement"];
};

function subtitleForTarget(
  target: FinalReviewChipEditTarget,
  msgs: SubtitleMessages,
  customMeta?: CreateFlowState["customMethodCardMetaById"],
  coreValueSupportText?: string,
): string {
  switch (target.groupKey) {
    case "coreValues": {
      const fromSaved = coreValueSupportText?.trim();
      if (fromSaved) return fromSaved;
      return msgs.tCv.detailModal.subtitle;
    }
    case "communication": {
      const fromCustom = customMeta?.[target.overrideKey]?.supportText?.trim();
      if (fromCustom) return fromCustom;
      return findMethodSupportText(msgs.tComm.methods, target.overrideKey);
    }
    case "membership": {
      const fromCustom = customMeta?.[target.overrideKey]?.supportText?.trim();
      if (fromCustom) return fromCustom;
      return findMethodSupportText(msgs.tMem.methods, target.overrideKey);
    }
    case "decisionApproaches": {
      const fromCustom = customMeta?.[target.overrideKey]?.supportText?.trim();
      if (fromCustom) return fromCustom;
      return findMethodSupportText(msgs.tDa.methods, target.overrideKey);
    }
    case "conflictManagement": {
      const fromCustom = customMeta?.[target.overrideKey]?.supportText?.trim();
      if (fromCustom) return fromCustom;
      return findMethodSupportText(msgs.tCm.methods, target.overrideKey);
    }
  }
}

function findMethodSupportText(
  methods: readonly { id: string; supportText: string }[],
  id: string,
): string {
  for (const method of methods) {
    if (method.id === id) return method.supportText;
  }
  return "";
}
