import { describe, expect, it } from "vitest";
import {
  createFlowStateFromPublishedRule,
  isPublishedRuleHydratePatchIncomplete,
  isPublishedRuleSelectionMissing,
  methodSectionsPinsForHydratedSelections,
  methodSectionsPinsFromPublishedHydratePatch,
} from "../../lib/create/publishedDocumentToCreateFlowState";
import type { CreateFlowState } from "../../app/(app)/create/types";

describe("isPublishedRuleSelectionMissing", () => {
  it("is true when published patch has communication ids but state has none", () => {
    const patch = createFlowStateFromPublishedRule({
      id: "r",
      title: "T",
      summary: "",
      document: {
        methodSelections: {
          communication: [
            {
              id: "slack",
              label: "Slack",
              sections: {
                corePrinciple: "",
                logisticsAdmin: "",
                codeOfConduct: "",
              },
            },
          ],
        },
      },
    });
    const state = {
      sections: [],
      title: "T",
      editingPublishedRuleId: "r",
    } as CreateFlowState;
    expect(isPublishedRuleSelectionMissing(state, patch)).toBe(true);
  });

  it("is false when sections are clear and state already has matching facet ids", () => {
    const patch = createFlowStateFromPublishedRule({
      id: "r",
      title: "T",
      summary: "",
      document: {
        methodSelections: {
          communication: [
            {
              id: "slack",
              label: "Slack",
              sections: {
                corePrinciple: "",
                logisticsAdmin: "",
                codeOfConduct: "",
              },
            },
          ],
        },
      },
    });
    const state = {
      sections: [],
      title: "T",
      editingPublishedRuleId: "r",
      selectedCommunicationMethodIds: ["slack"],
    } as CreateFlowState;
    expect(isPublishedRuleSelectionMissing(state, patch)).toBe(false);
  });
});

describe("isPublishedRuleHydratePatchIncomplete", () => {
  it("is true when facet ids are present but custom method meta from patch is missing in state", () => {
    const customId = "b7c0a9f3-0000-4000-8000-000000000001";
    const patch = createFlowStateFromPublishedRule({
      id: "r",
      title: "T",
      summary: "",
      document: {
        methodSelections: {
          communication: [
            {
              id: customId,
              label: "My custom comms method",
              sections: {
                corePrinciple: "x",
                logisticsAdmin: "",
                codeOfConduct: "",
              },
            },
          ],
        },
      },
    });
    const state = {
      sections: [],
      title: "T",
      editingPublishedRuleId: "r",
      selectedCommunicationMethodIds: [customId],
    } as CreateFlowState;
    expect(isPublishedRuleSelectionMissing(state, patch)).toBe(false);
    expect(isPublishedRuleHydratePatchIncomplete(state, patch)).toBe(true);
  });

  it("is false when patch meta keys exist on state", () => {
    const customId = "b7c0a9f3-0000-4000-8000-000000000001";
    const patch = createFlowStateFromPublishedRule({
      id: "r",
      title: "T",
      summary: "",
      document: {
        methodSelections: {
          communication: [
            {
              id: customId,
              label: "My custom comms method",
              sections: {
                corePrinciple: "",
                logisticsAdmin: "",
                codeOfConduct: "",
              },
            },
          ],
        },
      },
    });
    const state = {
      sections: [],
      title: "T",
      editingPublishedRuleId: "r",
      selectedCommunicationMethodIds: [customId],
      customMethodCardMetaById: patch.customMethodCardMetaById,
    } as CreateFlowState;
    expect(isPublishedRuleHydratePatchIncomplete(state, patch)).toBe(false);
  });
});

describe("methodSectionsPinsForHydratedSelections / methodSectionsPinsFromPublishedHydratePatch", () => {
  it("alias matches hydrated-selection helper output", () => {
    const partial: Partial<CreateFlowState> = {
      selectedCommunicationMethodIds: ["a"],
      selectedConflictManagementIds: ["b"],
    };
    expect(methodSectionsPinsFromPublishedHydratePatch(partial)).toEqual(
      methodSectionsPinsForHydratedSelections(partial),
    );
  });
});

describe("methodSectionsPinsFromPublishedHydratePatch", () => {
  it("sets communication when published patch includes communication ids", () => {
    const patch = createFlowStateFromPublishedRule({
      id: "r",
      title: "T",
      summary: "",
      document: {
        methodSelections: {
          communication: [
            {
              id: "slack",
              label: "Slack",
              sections: {
                corePrinciple: "",
                logisticsAdmin: "",
                codeOfConduct: "",
              },
            },
          ],
        },
      },
    });
    expect(methodSectionsPinsFromPublishedHydratePatch(patch)).toEqual({
      communication: true,
    });
  });

  it("sets all four method facets when each has selections on the patch", () => {
    const patch = createFlowStateFromPublishedRule({
      id: "r",
      title: "T",
      summary: "",
      document: {
        methodSelections: {
          communication: [
            {
              id: "slack",
              label: "S",
              sections: {
                corePrinciple: "",
                logisticsAdmin: "",
                codeOfConduct: "",
              },
            },
          ],
          membership: [
            {
              id: "x",
              label: "X",
              sections: {
                eligibility: "",
                joiningProcess: "",
                expectations: "",
              },
            },
          ],
          decisionApproaches: [
            {
              id: "d",
              label: "D",
              sections: {
                corePrinciple: "",
                applicableScope: [],
                selectedApplicableScope: [],
                stepByStepInstructions: "",
                consensusLevel: 0,
                objectionsDeadlocks: "",
              },
            },
          ],
          conflictManagement: [
            {
              id: "c",
              label: "C",
              sections: {
                corePrinciple: "",
                applicableScope: [],
                selectedApplicableScope: [],
                processProtocol: "",
                restorationFallbacks: "",
              },
            },
          ],
        },
      },
    });
    expect(methodSectionsPinsFromPublishedHydratePatch(patch)).toEqual({
      communication: true,
      membership: true,
      decisionApproaches: true,
      conflictManagement: true,
    });
  });

  it("returns {} when patch has no method-card selections", () => {
    expect(methodSectionsPinsFromPublishedHydratePatch({ sections: [] })).toEqual(
      {},
    );
  });
});

describe("createFlowStateFromPublishedRule", () => {
  it("maps coreValues and methodSelections into draft fields", () => {
    const partial = createFlowStateFromPublishedRule({
      id: "rule-1",
      title: "Oak",
      summary: "River cleanup",
      document: {
        coreValues: [
          { chipId: "1", label: "Ecology", meaning: "m", signals: "s" },
        ],
        methodSelections: {
          communication: [
            {
              id: "slack",
              label: "Slack",
              sections: {
                corePrinciple: "p",
                logisticsAdmin: "l",
                codeOfConduct: "c",
              },
            },
          ],
        },
      },
    });
    expect(partial.editingPublishedRuleId).toBe("rule-1");
    expect(partial.title).toBe("Oak");
    expect(partial.communityContext).toBe("River cleanup");
    expect(partial.selectedCoreValueIds).toEqual(["1"]);
    expect(partial.coreValuesChipsSnapshot?.[0]?.label).toBe("Ecology");
    expect(partial.selectedCommunicationMethodIds).toEqual(["slack"]);
    expect(partial.communicationMethodDetailsById?.slack?.corePrinciple).toBe(
      "p",
    );
    expect(partial.sections).toEqual([]);
  });

  it("hydrates customMethodCardMetaById for user-authored method ids from methodSelections", () => {
    const customId = "b7c0a9f3-0000-4000-8000-000000000001";
    const partial = createFlowStateFromPublishedRule({
      id: "rule-custom",
      title: "C",
      summary: "",
      document: {
        methodSelections: {
          communication: [
            {
              id: customId,
              label: "Custom channel policy",
              sections: {
                corePrinciple: "cp",
                logisticsAdmin: "la",
                codeOfConduct: "cc",
              },
            },
          ],
        },
      },
    });
    expect(partial.selectedCommunicationMethodIds).toEqual([customId]);
    expect(partial.customMethodCardMetaById?.[customId]).toEqual({
      label: "Custom channel policy",
      supportText: "",
    });
  });

  it("hydrates wizard supportText from published methodSelections", () => {
    const customId = "b7c0a9f3-0000-4000-8000-000000000002";
    const partial = createFlowStateFromPublishedRule({
      id: "rule-custom-desc",
      title: "C",
      summary: "",
      document: {
        methodSelections: {
          decisionApproaches: [
            {
              id: customId,
              label: "Forum proposals",
              supportText: "Anyone can start a thread.",
              sections: {
                corePrinciple: "",
                applicableScope: [],
                selectedApplicableScope: [],
                stepByStepInstructions: "",
                objectionsDeadlocks: "",
              },
            },
          ],
        },
      },
    });
    expect(partial.customMethodCardMetaById?.[customId]).toEqual({
      label: "Forum proposals",
      supportText: "Anyone can start a thread.",
    });
  });

  it("sets sections to [] even when methodSelections is missing (edit hydrate)", () => {
    const partial = createFlowStateFromPublishedRule({
      id: "rule-2",
      title: "Pine",
      summary: "",
      document: {
        coreValues: [],
      },
    });
    expect(partial.sections).toEqual([]);
  });
});
