import {
  label1BoldOptions,
  useProcessedChecklist,
} from "./use-processed-check-list";

import { MARKS } from "@contentful/rich-text-types";
import { renderHook } from "@testing-library/react";

// Mock renderContentfulRichText to return predictable output
jest.mock("./use-contentful-rich-text", () => ({
  renderContentfulRichText: jest.fn(
    (doc: any, _target?: boolean, className?: string) => {
      // Return a simple string representation based on the doc
      if (!doc) return null;
      // Extract text from the doc content if available
      const text = doc?.content?.[0]?.content?.[0]?.value;
      return text ? `rendered:${text}:${className ?? ""}` : null;
    }
  ),
}));

jest.mock("@shared/utils/contentful/to-document", () => ({
  toDocument: jest.fn((v: any) => {
    if (!v) return null;
    if (typeof v === "string") {
      return {
        nodeType: "document",
        data: {},
        content: [
          {
            nodeType: "paragraph",
            data: {},
            content: [{ nodeType: "text", value: v, marks: [], data: {} }],
          },
        ],
      };
    }
    return v;
  }),
}));

const makeChecklistData = (items: any[]) => ({
  list: {
    items,
  },
});

describe("useProcessedChecklist", () => {
  describe("Full items mode (titlesOnly=false)", () => {
    it("returns empty array when checklistData is undefined", () => {
      const { result } = renderHook(() => useProcessedChecklist(undefined));
      expect(result.current).toEqual([]);
    });

    it("returns empty array when checklistData has no list", () => {
      const { result } = renderHook(() => useProcessedChecklist({}));
      expect(result.current).toEqual([]);
    });

    it("returns empty array when list.items is empty", () => {
      const data = makeChecklistData([]);
      const { result } = renderHook(() => useProcessedChecklist(data));
      expect(result.current).toEqual([]);
    });

    it("returns ProcessedChecklistItem array with title, iconUrl, anchorId", () => {
      const data = makeChecklistData([
        {
          checkListTitle: "Item 1",
          icon: { url: "https://cdn.com/icon1.png" },
          anchorId: "anchor-1",
        },
        {
          checkListTitle: "Item 2",
          icon: { url: "https://cdn.com/icon2.png" },
          anchorId: "anchor-2",
        },
      ]);
      const { result } = renderHook(() => useProcessedChecklist(data));
      expect(result.current).toHaveLength(2);
      expect(result.current[0]).toEqual({
        title: "rendered:Item 1:",
        iconUrl: "https://cdn.com/icon1.png",
        anchorId: "anchor-1",
      });
      expect(result.current[1]).toEqual({
        title: "rendered:Item 2:",
        iconUrl: "https://cdn.com/icon2.png",
        anchorId: "anchor-2",
      });
    });

    it("sets iconUrl to undefined when icon is missing", () => {
      const data = makeChecklistData([
        { checkListTitle: "No icon", icon: undefined },
      ]);
      const { result } = renderHook(() => useProcessedChecklist(data));
      expect(result.current[0].iconUrl).toBeUndefined();
    });

    it("sets anchorId to undefined when anchorId is missing", () => {
      const data = makeChecklistData([{ checkListTitle: "No anchor" }]);
      const { result } = renderHook(() => useProcessedChecklist(data));
      expect(result.current[0].anchorId).toBeUndefined();
    });

    it("uses empty string for title when checkListTitle is null", () => {
      const data = makeChecklistData([{ checkListTitle: null }]);
      const { result } = renderHook(() => useProcessedChecklist(data));
      // toDocument("") returns null, renderContentfulRichText returns null, falls back to ""
      expect(result.current[0].title).toBe("");
    });

    it("handles item with undefined checkListTitle", () => {
      const data = makeChecklistData([{}]);
      const { result } = renderHook(() => useProcessedChecklist(data));
      expect(result.current[0].title).toBe("");
    });

    it("handles null item in items array", () => {
      const data = makeChecklistData([null]);
      const { result } = renderHook(() => useProcessedChecklist(data));
      expect(result.current[0].title).toBe("");
      expect(result.current[0].iconUrl).toBeUndefined();
      expect(result.current[0].anchorId).toBeUndefined();
    });

    it("handles undefined item in items array", () => {
      const data = makeChecklistData([undefined]);
      const { result } = renderHook(() => useProcessedChecklist(data));
      expect(result.current[0].title).toBe("");
    });

    it("passes richTextClassName to renderContentfulRichText in full mode", () => {
      const data = makeChecklistData([{ checkListTitle: "Styled" }]);
      const { result } = renderHook(() =>
        useProcessedChecklist(data, false, undefined, "full-class")
      );
      expect(result.current[0].title).toBe("rendered:Styled:full-class");
    });

    it("passes richTextOptions in full mode", () => {
      const data = makeChecklistData([{ checkListTitle: "Opts" }]);
      const customOpts = { renderMark: { [MARKS.BOLD]: (t: any) => t } };
      const { result } = renderHook(() =>
        useProcessedChecklist(data, false, customOpts, "opts-class")
      );
      expect(result.current[0].title).toBe("rendered:Opts:opts-class");
    });

    it("handles item with icon but no url", () => {
      const data = makeChecklistData([{ checkListTitle: "No url", icon: {} }]);
      const { result } = renderHook(() => useProcessedChecklist(data));
      expect(result.current[0].iconUrl).toBeUndefined();
    });
  });

  describe("Titles only mode (titlesOnly=true)", () => {
    it("returns string array of rendered titles", () => {
      const data = makeChecklistData([
        { checkListTitle: "Title A" },
        { checkListTitle: "Title B" },
      ]);
      const { result } = renderHook(() => useProcessedChecklist(data, true));
      expect(result.current).toHaveLength(2);
      expect(result.current[0]).toBe("rendered:Title A:");
      expect(result.current[1]).toBe("rendered:Title B:");
    });

    it("returns empty string for null checkListTitle", () => {
      const data = makeChecklistData([{ checkListTitle: null }]);
      const { result } = renderHook(() => useProcessedChecklist(data, true));
      expect(result.current[0]).toBe("");
    });

    it("returns empty array when no items", () => {
      const { result } = renderHook(() =>
        useProcessedChecklist(undefined, true)
      );
      expect(result.current).toEqual([]);
    });

    it("handles null item in items array in titlesOnly mode", () => {
      const data = makeChecklistData([null]);
      const { result } = renderHook(() => useProcessedChecklist(data, true));
      expect(result.current[0]).toBe("");
    });

    it("handles undefined item in items array in titlesOnly mode", () => {
      const data = makeChecklistData([undefined]);
      const { result } = renderHook(() => useProcessedChecklist(data, true));
      expect(result.current[0]).toBe("");
    });

    it("passes richTextOptions in titlesOnly mode", () => {
      const data = makeChecklistData([{ checkListTitle: "Opt" }]);
      const customOpts = { renderMark: {} };
      const { result } = renderHook(() =>
        useProcessedChecklist(data, true, customOpts, "title-class")
      );
      expect(result.current[0]).toBe("rendered:Opt:title-class");
    });
  });

  describe("richTextOptions and richTextClassName", () => {
    it("passes richTextClassName to renderContentfulRichText", () => {
      const data = makeChecklistData([{ checkListTitle: "Styled" }]);
      const { result } = renderHook(() =>
        useProcessedChecklist(data, true, undefined, "custom-class")
      );
      expect(result.current[0]).toBe("rendered:Styled:custom-class");
    });

    it("passes richTextOptions through", () => {
      const data = makeChecklistData([{ checkListTitle: "Options" }]);
      const customOpts = { renderMark: {} };
      const { result } = renderHook(() =>
        useProcessedChecklist(data, false, customOpts)
      );
      // Should still produce results (richTextOptions is passed but our mock ignores it)
      expect(result.current).toHaveLength(1);
    });
  });

  describe("Memoization", () => {
    it("returns same reference when inputs don't change", () => {
      const data = makeChecklistData([{ checkListTitle: "Memo" }]);
      const { result, rerender } = renderHook(
        ({ d }) => useProcessedChecklist(d),
        { initialProps: { d: data } }
      );
      const first = result.current;
      rerender({ d: data });
      expect(result.current).toBe(first);
    });

    it("recomputes when checklistData changes", () => {
      const data1 = makeChecklistData([{ checkListTitle: "V1" }]);
      const data2 = makeChecklistData([{ checkListTitle: "V2" }]);
      const { result, rerender } = renderHook(
        ({ d }) => useProcessedChecklist(d),
        { initialProps: { d: data1 } }
      );
      const first = result.current;
      rerender({ d: data2 });
      expect(result.current).not.toBe(first);
    });

    it("recomputes when titlesOnly changes", () => {
      const data = makeChecklistData([{ checkListTitle: "Toggle" }]);
      const { result, rerender } = renderHook(
        ({ t }) => useProcessedChecklist(data, t),
        { initialProps: { t: false as boolean } }
      );
      const first = result.current;
      rerender({ t: true });
      expect(result.current).not.toBe(first);
    });
  });
});

describe("label1BoldOptions", () => {
  it("exports BOLD mark renderer that wraps in span with label1 class", () => {
    const renderer = label1BoldOptions.renderMark[MARKS.BOLD];
    expect(renderer).toBeDefined();
  });

  it("renders bold text in a span with label1 className", () => {
    const renderer = label1BoldOptions.renderMark[MARKS.BOLD];
    const result = renderer("Bold text");
    // createElement returns a React element with type 'span' and className 'label1'
    expect(result).toBeDefined();
    expect((result as any).type).toBe("span");
    expect((result as any).props.className).toBe("label1");
    expect((result as any).props.children).toBe("Bold text");
  });
});
