import { REGISTRY_URL } from "@/src/registry/constants"
import prompts from "prompts"
import { beforeEach, describe, expect, it, vi } from "vitest"

import {
  DEFAULT_PRESETS,
  promptForBase,
  resolveCreateUrl,
  resolveInitUrl,
} from "./presets"

vi.mock("prompts", () => ({
  default: vi.fn(),
}))

const SHADCN_URL = REGISTRY_URL.replace(/\/r\/?$/, "")

const mockPreset = {
  name: "default",
  title: "Default",
  description: "The default preset.",
  base: "radix" as const,
  style: "new-york-v4",
  baseColor: "neutral",
  theme: "default",
  iconLibrary: "lucide",
  font: "inter",
  fontHeading: "inherit",
  rtl: false,
  menuAccent: "subtle" as const,
  menuColor: "default" as const,
  radius: "0.5",
}

describe("promptForBase", () => {
  beforeEach(() => {
    vi.mocked(prompts).mockReset()
  })

  it("should offer and return the aria base", async () => {
    vi.mocked(prompts).mockResolvedValue({ base: "aria" })

    await expect(promptForBase()).resolves.toBe("aria")
    expect(prompts).toHaveBeenCalledWith(
      expect.objectContaining({
        choices: [
          { title: "Base UI (Recommended)", value: "base" },
          { title: "React Aria", value: "aria" },
          { title: "Radix UI", value: "radix" },
        ],
      })
    )
  })
})

describe("createPresetUrl", () => {
  it("should not include rtl by default", () => {
    const url = resolveCreateUrl()
    const parsed = new URL(url)
    expect(parsed.origin + parsed.pathname).toBe(`${SHADCN_URL}/create`)
    expect(parsed.searchParams.has("rtl")).toBe(false)
  })

  it("should append search params when provided", () => {
    const url = resolveCreateUrl({
      rtl: true,
      pointer: true,
      template: "next",
    })
    const parsed = new URL(url)
    expect(parsed.searchParams.get("rtl")).toBe("true")
    expect(parsed.searchParams.get("pointer")).toBe("true")
    expect(parsed.searchParams.get("template")).toBe("next")
  })
})

describe("buildInitUrl", () => {
  it("should build url with all preset fields as query params", () => {
    const url = resolveInitUrl(mockPreset)
    const parsed = new URL(url)
    expect(parsed.origin + parsed.pathname).toBe(`${SHADCN_URL}/init`)
    expect(parsed.searchParams.get("base")).toBe("radix")
    expect(parsed.searchParams.get("style")).toBe("new-york-v4")
    expect(parsed.searchParams.get("baseColor")).toBe("neutral")
    expect(parsed.searchParams.get("theme")).toBe("default")
    expect(parsed.searchParams.get("iconLibrary")).toBe("lucide")
    expect(parsed.searchParams.get("font")).toBe("inter")
    expect(parsed.searchParams.get("rtl")).toBe("false")
    expect(parsed.searchParams.get("menuAccent")).toBe("subtle")
    expect(parsed.searchParams.get("menuColor")).toBe("default")
    expect(parsed.searchParams.get("radius")).toBe("0.5")
  })

  it("should set rtl=true when preset.rtl is true", () => {
    const url = resolveInitUrl({ ...mockPreset, rtl: true })
    const parsed = new URL(url)
    expect(parsed.searchParams.get("rtl")).toBe("true")
  })

  it("should include template when provided", () => {
    const url = resolveInitUrl(mockPreset, { template: "next" })
    const parsed = new URL(url)
    expect(parsed.searchParams.get("template")).toBe("next")
  })

  it("should not include template when not provided", () => {
    const url = resolveInitUrl(mockPreset)
    const parsed = new URL(url)
    expect(parsed.searchParams.has("template")).toBe(false)
  })

  it("should include chartColor when provided", () => {
    const url = resolveInitUrl({ ...mockPreset, chartColor: "emerald" })
    const parsed = new URL(url)
    expect(parsed.searchParams.get("chartColor")).toBe("emerald")
  })

  it("should not include chartColor when it is neutral", () => {
    const url = resolveInitUrl({ ...mockPreset, chartColor: "neutral" })
    const parsed = new URL(url)
    expect(parsed.searchParams.has("chartColor")).toBe(false)
  })

  it("should include chartColor from default presets", () => {
    const url = resolveInitUrl({ ...DEFAULT_PRESETS.sera, base: "base" })
    const parsed = new URL(url)
    expect(parsed.searchParams.get("chartColor")).toBe("taupe")
  })

  it("should not include chartColor when not provided", () => {
    const url = resolveInitUrl(mockPreset)
    const parsed = new URL(url)
    expect(parsed.searchParams.has("chartColor")).toBe(false)
  })

  it("should include fontHeading when it is explicitly set", () => {
    const url = resolveInitUrl({
      ...mockPreset,
      fontHeading: "playfair-display",
    })
    const parsed = new URL(url)
    expect(parsed.searchParams.get("fontHeading")).toBe("playfair-display")
  })

  it("should not include fontHeading when it inherits the body font", () => {
    const url = resolveInitUrl(mockPreset)
    const parsed = new URL(url)
    expect(parsed.searchParams.has("fontHeading")).toBe(false)
  })

  it("should include preset code when provided", () => {
    const url = resolveInitUrl(mockPreset, { preset: "a0" })
    const parsed = new URL(url)
    expect(parsed.searchParams.get("preset")).toBe("a0")
  })

  it("should not include preset when not provided", () => {
    const url = resolveInitUrl(mockPreset)
    const parsed = new URL(url)
    expect(parsed.searchParams.has("preset")).toBe(false)
  })

  it("should include pointer when enabled", () => {
    const url = resolveInitUrl(mockPreset, { pointer: true })
    const parsed = new URL(url)
    expect(parsed.searchParams.get("pointer")).toBe("true")
  })

  it("should not include pointer when disabled", () => {
    const url = resolveInitUrl(mockPreset, { pointer: false })
    const parsed = new URL(url)
    expect(parsed.searchParams.has("pointer")).toBe(false)
  })

  it("should include pointer with preset codes", () => {
    const url = resolveInitUrl(mockPreset, { preset: "a0", pointer: true })
    const parsed = new URL(url)
    expect(parsed.searchParams.get("preset")).toBe("a0")
    expect(parsed.searchParams.get("pointer")).toBe("true")
  })
})
