import type {
  CommunicationMethodDetailEntry,
  ConflictManagementDetailEntry,
  CoreValueDetailEntry,
  CreateFlowState,
  DecisionApproachDetailEntry,
  MembershipMethodDetailEntry,
} from "../../app/(app)/create/types";
import type { CustomMethodCardFieldBlock } from "./customMethodCardFieldBlocks";
import { formatConflictApplicableScopeForTextarea } from "./ruleSectionsFromMethodSelections";

/** Seed for {@link CustomMethodCardWizard} when Customize opens on an existing card. */
export type MethodCardWizardInitialValues = {
  title: string;
  description: string;
  fieldBlocks: CustomMethodCardFieldBlock[];
};

export type MethodCardWizardFacetPrefill =
  | {
      group: "communication";
      draft: CommunicationMethodDetailEntry;
      headings: {
        corePrinciple: string;
        logisticsAdmin: string;
        codeOfConduct: string;
      };
    }
  | {
      group: "membership";
      draft: MembershipMethodDetailEntry;
      headings: {
        eligibility: string;
        joiningProcess: string;
        expectations: string;
      };
    }
  | {
      group: "decisionApproaches";
      draft: DecisionApproachDetailEntry;
      headings: {
        corePrinciple: string;
        applicableScope: string;
        stepByStepInstructions: string;
        consensusLevel: string;
        objectionsDeadlocks: string;
      };
    }
    | {
      group: "conflictManagement";
      draft: ConflictManagementDetailEntry;
      headings: {
        corePrinciple: string;
        applicableScope: string;
        processProtocol: string;
        restorationFallbacks: string;
      };
    }
  | {
      group: "coreValues";
      draft: CoreValueDetailEntry;
      headings: {
        meaning: string;
        signals: string;
      };
    };

const TEXT_BODY_MAX = 8000;

function textBlock(
  id: string,
  blockTitle: string,
  placeholderText: string,
): CustomMethodCardFieldBlock {
  return {
    kind: "text",
    id,
    blockTitle,
    placeholderText: placeholderText.slice(0, TEXT_BODY_MAX),
  };
}

function hasTrimmedText(value: string): boolean {
  return value.trim().length > 0;
}

function clampPercent(n: number): number {
  if (!Number.isFinite(n)) return 1;
  return Math.min(100, Math.max(1, Math.round(n)));
}

function facetPrefillHasContent(prefill: MethodCardWizardFacetPrefill): boolean {
  switch (prefill.group) {
    case "communication":
      return (
        hasTrimmedText(prefill.draft.corePrinciple) ||
        hasTrimmedText(prefill.draft.logisticsAdmin) ||
        hasTrimmedText(prefill.draft.codeOfConduct)
      );
    case "membership":
      return (
        hasTrimmedText(prefill.draft.eligibility) ||
        hasTrimmedText(prefill.draft.joiningProcess) ||
        hasTrimmedText(prefill.draft.expectations)
      );
    case "decisionApproaches":
      return (
        hasTrimmedText(prefill.draft.corePrinciple) ||
        hasTrimmedText(prefill.draft.stepByStepInstructions) ||
        hasTrimmedText(prefill.draft.objectionsDeadlocks) ||
        prefill.draft.applicableScope.length > 0 ||
        prefill.draft.selectedApplicableScope.length > 0
      );
    case "conflictManagement":
      return (
        hasTrimmedText(prefill.draft.corePrinciple) ||
        hasTrimmedText(prefill.draft.processProtocol) ||
        hasTrimmedText(prefill.draft.restorationFallbacks) ||
        formatConflictApplicableScopeForTextarea(
          prefill.draft.selectedApplicableScope,
          prefill.draft.applicableScope,
        ).trim().length > 0
      );
    case "coreValues":
      return (
        hasTrimmedText(prefill.draft.meaning) ||
        hasTrimmedText(prefill.draft.signals)
      );
  }
}

function mapFacetPrefillToWizardFieldBlocks(
  prefill: MethodCardWizardFacetPrefill,
): CustomMethodCardFieldBlock[] {
  switch (prefill.group) {
    case "communication":
      return [
        textBlock(
          "facet-corePrinciple",
          prefill.headings.corePrinciple,
          prefill.draft.corePrinciple,
        ),
        textBlock(
          "facet-logisticsAdmin",
          prefill.headings.logisticsAdmin,
          prefill.draft.logisticsAdmin,
        ),
        textBlock(
          "facet-codeOfConduct",
          prefill.headings.codeOfConduct,
          prefill.draft.codeOfConduct,
        ),
      ];
    case "membership":
      return [
        textBlock(
          "facet-eligibility",
          prefill.headings.eligibility,
          prefill.draft.eligibility,
        ),
        textBlock(
          "facet-joiningProcess",
          prefill.headings.joiningProcess,
          prefill.draft.joiningProcess,
        ),
        textBlock(
          "facet-expectations",
          prefill.headings.expectations,
          prefill.draft.expectations,
        ),
      ];
    case "decisionApproaches": {
      const scopeOptions =
        prefill.draft.applicableScope.length > 0
          ? [...prefill.draft.applicableScope]
          : [...prefill.draft.selectedApplicableScope];
      const blocks: CustomMethodCardFieldBlock[] = [
        textBlock(
          "facet-corePrinciple",
          prefill.headings.corePrinciple,
          prefill.draft.corePrinciple,
        ),
      ];
      if (scopeOptions.length > 0) {
        blocks.push({
          kind: "badges",
          id: "facet-applicableScope",
          blockTitle: prefill.headings.applicableScope,
          options: scopeOptions,
        });
      }
      blocks.push(
        textBlock(
          "facet-stepByStepInstructions",
          prefill.headings.stepByStepInstructions,
          prefill.draft.stepByStepInstructions,
        ),
      );
      if (
        typeof prefill.draft.consensusLevel === "number" &&
        facetPrefillHasContent(prefill)
      ) {
        blocks.push({
          kind: "proportion",
          id: "facet-consensusLevel",
          blockTitle: prefill.headings.consensusLevel,
          defaultPercent: clampPercent(prefill.draft.consensusLevel),
        });
      }
      blocks.push(
        textBlock(
          "facet-objectionsDeadlocks",
          prefill.headings.objectionsDeadlocks,
          prefill.draft.objectionsDeadlocks,
        ),
      );
      return blocks;
    }
    case "conflictManagement":
      return [
        textBlock(
          "facet-corePrinciple",
          prefill.headings.corePrinciple,
          prefill.draft.corePrinciple,
        ),
        textBlock(
          "facet-applicableScope",
          prefill.headings.applicableScope,
          formatConflictApplicableScopeForTextarea(
            prefill.draft.selectedApplicableScope,
            prefill.draft.applicableScope,
          ),
        ),
        textBlock(
          "facet-processProtocol",
          prefill.headings.processProtocol,
          prefill.draft.processProtocol,
        ),
        textBlock(
          "facet-restorationFallbacks",
          prefill.headings.restorationFallbacks,
          prefill.draft.restorationFallbacks,
        ),
      ];
    case "coreValues":
      return [
        textBlock(
          "facet-meaning",
          prefill.headings.meaning,
          prefill.draft.meaning,
        ),
        textBlock(
          "facet-signals",
          prefill.headings.signals,
          prefill.draft.signals,
        ),
      ];
  }
}

/**
 * Map a method card's facet editors onto wizard field blocks so Customize
 * can show and edit the same sections on step 3.
 */
export function facetDetailsToWizardFieldBlocks(
  prefill: MethodCardWizardFacetPrefill,
): CustomMethodCardFieldBlock[] {
  if (!facetPrefillHasContent(prefill)) {
    return [];
  }
  return mapFacetPrefillToWizardFieldBlocks(prefill);
}

function facetBlockHasContent(block: CustomMethodCardFieldBlock): boolean {
  switch (block.kind) {
    case "text":
      return hasTrimmedText(block.placeholderText);
    case "badges":
      return block.options.length > 0;
    case "proportion":
      return true;
    case "upload":
      return Boolean(block.fileName?.trim() || block.assetUrl?.trim());
  }
}

function overlayBlockValue(
  existing: CustomMethodCardFieldBlock,
  incoming: CustomMethodCardFieldBlock,
): CustomMethodCardFieldBlock {
  if (existing.kind === "text" && incoming.kind === "text") {
    return { ...existing, placeholderText: incoming.placeholderText };
  }
  if (existing.kind === "badges" && incoming.kind === "badges") {
    return { ...existing, options: [...incoming.options] };
  }
  if (existing.kind === "proportion" && incoming.kind === "proportion") {
    return { ...existing, defaultPercent: incoming.defaultPercent };
  }
  if (existing.kind === "upload" && incoming.kind === "upload") {
    return {
      ...existing,
      fileName: incoming.fileName,
      ...(incoming.assetUrl !== undefined
        ? { assetUrl: incoming.assetUrl }
        : {}),
    };
  }
  return incoming;
}

/**
 * Keep extra wizard-only blocks, but refresh facet-* field values from the
 * current modal editors so Customize does not show a stale copy.
 */
export function overlayFacetPrefillValues(
  blocks: CustomMethodCardFieldBlock[],
  prefill: MethodCardWizardFacetPrefill,
): CustomMethodCardFieldBlock[] {
  const incoming = mapFacetPrefillToWizardFieldBlocks(prefill);
  const incomingById = new Map(incoming.map((block) => [block.id, block]));
  const seen = new Set<string>();
  const next = blocks.map((block) => {
    const overlay = incomingById.get(block.id);
    if (!overlay) {
      return block;
    }
    seen.add(block.id);
    return overlayBlockValue(block, overlay);
  });
  for (const block of incoming) {
    if (seen.has(block.id) || !facetBlockHasContent(block)) {
      continue;
    }
    next.push(block);
  }
  return next;
}

function textPlaceholderForBlockId(
  blocks: CustomMethodCardFieldBlock[],
  id: string,
): string | undefined {
  const block = blocks.find((b) => b.id === id);
  if (!block || block.kind !== "text") {
    return undefined;
  }
  return block.placeholderText;
}

/** Map Customize wizard field blocks back onto meaning/signals for a value chip. */
export function coreValueDetailsFromWizardFieldBlocks(
  blocks: CustomMethodCardFieldBlock[],
  fallback: CoreValueDetailEntry,
): CoreValueDetailEntry {
  return {
    meaning: textPlaceholderForBlockId(blocks, "facet-meaning") ?? fallback.meaning,
    signals:
      textPlaceholderForBlockId(blocks, "facet-signals") ?? fallback.signals,
    ...(fallback.supportText !== undefined
      ? { supportText: fallback.supportText }
      : {}),
  };
}

/**
 * Title, support text, and field blocks for the custom-policy wizard, preferring
 * in-modal drafts over persisted meta/blocks. When the card has no wizard
 * blocks yet, facet body fields are mapped onto step-3 blocks.
 */
export function buildMethodCardWizardInitialValues(args: {
  cardId: string;
  fallbackTitle: string;
  fallbackDescription: string;
  meta: CreateFlowState["customMethodCardMetaById"];
  persistedBlocks: CreateFlowState["customMethodCardFieldBlocksById"];
  draftFieldBlocks: CustomMethodCardFieldBlock[] | null;
  facetPrefill?: MethodCardWizardFacetPrefill;
}): MethodCardWizardInitialValues {
  const metaRow = args.meta?.[args.cardId];
  const persisted = args.persistedBlocks?.[args.cardId];
  let fieldBlocks =
    args.draftFieldBlocks !== null
      ? structuredClone(args.draftFieldBlocks)
      : Array.isArray(persisted) && persisted.length > 0
        ? structuredClone(persisted)
        : [];
  if (fieldBlocks.length === 0 && args.facetPrefill) {
    fieldBlocks = facetDetailsToWizardFieldBlocks(args.facetPrefill);
  } else if (fieldBlocks.length > 0 && args.facetPrefill) {
    fieldBlocks = overlayFacetPrefillValues(fieldBlocks, args.facetPrefill);
  }
  return {
    title: metaRow?.label ?? args.fallbackTitle,
    description: metaRow?.supportText ?? args.fallbackDescription,
    fieldBlocks,
  };
}
