import { describe, expect, it } from "vitest";
import type { PageBlock } from "@/admin/types";
import {
  blockInsertFailureMessage,
  createSectionWithBlock,
  placePageBlock,
  resolveSectionIndex,
  resolveSlotIndex,
  type SectionWithSlots,
} from "./placePageBlock";

const sampleBlock: PageBlock = {
  componentId: 1,
  componentName: "Hero",
  componentSlug: "hero",
  content: {},
};

function emptySection(layout: SectionWithSlots["layout"] = "100"): SectionWithSlots {
  return {
    width: "container",
    layout,
    blocks: [],
    id: "section-1",
  };
}

describe("resolveSectionIndex", () => {
  it("returns null for an empty list", () => {
    expect(resolveSectionIndex([], 0)).toBeNull();
  });

  it("falls back to the last section when the requested index is stale", () => {
    const sections = [emptySection(), emptySection()];
    expect(resolveSectionIndex(sections, 5)).toBe(1);
  });
});

describe("resolveSlotIndex", () => {
  it("returns undefined when the slot is already filled", () => {
    const section: SectionWithSlots = {
      ...emptySection("50-50"),
      blocks: [sampleBlock, null],
    };
    expect(resolveSlotIndex(section, 0)).toBeUndefined();
    expect(resolveSlotIndex(section, 1)).toBe(1);
  });
});

describe("placePageBlock", () => {
  it("creates the first section when the page is empty", () => {
    const result = placePageBlock([], sampleBlock);
    expect(result.ok).toBe(true);
    if (!result.ok) return;
    expect(result.mode).toBe("first-section");
    expect(result.nextSections).toHaveLength(1);
    expect(result.nextSections[0]?.blocks[0]).toEqual(sampleBlock);
  });

  it("places a block in the requested empty slot", () => {
    const sections = [emptySection("50-50")];
    const result = placePageBlock(sections, sampleBlock, { sectionIndex: 0, slotIndex: 1 });
    expect(result.ok).toBe(true);
    if (!result.ok) return;
    expect(result.nextSections[0]?.blocks[1]).toEqual(sampleBlock);
  });

  it("does not mutate sections when placement fails", () => {
    const sections: SectionWithSlots[] = [
      {
        ...emptySection("100"),
        blocks: [sampleBlock],
      },
    ];
    const result = placePageBlock(sections, sampleBlock, {
      sectionIndex: 0,
      slotIndex: 0,
      allowNewSection: false,
    });
    expect(result.ok).toBe(false);
    if (result.ok) return;
    expect(result.reason).toBe("slot-filled");
  });

  it("appends a new section when allowNewSection is true and the target section is full", () => {
    const sections: SectionWithSlots[] = [
      {
        ...emptySection("100"),
        blocks: [sampleBlock],
      },
    ];
    const result = placePageBlock(sections, { ...sampleBlock, componentId: 2 }, {
      sectionIndex: 0,
      allowNewSection: true,
    });
    expect(result.ok).toBe(true);
    if (!result.ok) return;
    expect(result.mode).toBe("new-section");
    expect(result.nextSections).toHaveLength(2);
    expect(result.nextSections[1]?.blocks[0]?.componentId).toBe(2);
  });

  it("marks stale section redirects without failing placement", () => {
    const sections = [emptySection(), emptySection()];
    const result = placePageBlock(sections, sampleBlock, { sectionIndex: 9 });
    expect(result.ok).toBe(true);
    if (!result.ok) return;
    expect(result.staleSectionRedirect).toBe(true);
    expect(result.nextSections[1]?.blocks[0]).toEqual(sampleBlock);
  });
});

describe("blockInsertFailureMessage", () => {
  it("uses library-specific guidance for add-from-library failures", () => {
    expect(blockInsertFailureMessage("no-section", "library")).toContain("Add a section");
    expect(blockInsertFailureMessage("no-section", "paste")).toContain("Try pasting again");
  });
});

describe("createSectionWithBlock", () => {
  it("creates a single-column section containing the block", () => {
    const section = createSectionWithBlock(sampleBlock);
    expect(section.layout).toBe("100");
    expect(section.blocks[0]).toEqual(sampleBlock);
  });

  it("uses full width for self-contained blocks (brandscape parity)", () => {
    const heroSection = createSectionWithBlock(sampleBlock);
    expect(heroSection.width).toBe("full");

    const quarterSection = createSectionWithBlock({
      componentId: 32,
      componentName: "How Each Course Sees This Quarter",
      componentSlug: "how-each-course-sees",
      content: {},
    });
    expect(quarterSection.width).toBe("full");
  });

  it("uses full width for course body blocks with BrandscapeShell (brandscape parity)", () => {
    const section = createSectionWithBlock({
      componentId: 10,
      componentName: "Why This Course Matters",
      componentSlug: "why-this-course-matters",
      content: {},
    });
    expect(section.width).toBe("full");
  });
});

describe("placePageBlock self-contained width promotion", () => {
  it("promotes an empty container section to full when placing a self-contained block", () => {
    const sections = [emptySection("100")];
    const result = placePageBlock(sections, sampleBlock, { sectionIndex: 0, slotIndex: 0 });
    expect(result.ok).toBe(true);
    if (!result.ok) return;
    expect(result.nextSections[0]?.width).toBe("full");
  });
});
