import type { ReadonlyURLSearchParams } from "next/navigation";
import { describe, expect, it } from "vitest";

import { EmbedTheme } from "@calcom/features/embed/lib/constants";

import { getThemeProviderProps } from "../getThemeProviderProps";
import { getUniqueIdentifierForBookingPage } from "../getThemeProviderProps";

describe("getThemeProviderProps", () => {
  const fnArg = {
    props: {
      isBookingPage: false,
      isThemeSupported: true,
      nonce: "test-nonce",
    },
    isEmbedMode: false,
    embedNamespace: null,
    searchParams: new URLSearchParams() as unknown as ReadonlyURLSearchParams,
  };

  describe("App Theme Support", () => {
    const expectedStorageKey = "app-theme";
    const appThemeExpectedProps = {
      attribute: "class",
      storageKey: expectedStorageKey,
      key: expectedStorageKey,
      nonce: "test-nonce",
      enableColorScheme: false,
    };

    it("should return app theme configuration when not in booking page or embed mode", () => {
      const result = getThemeProviderProps({
        ...fnArg,
        pathname: "/test",
      });
      expect(result).toEqual({
        forcedTheme: undefined,
        enableSystem: true,
        ...appThemeExpectedProps,
      });
    });

    it("should force light theme and no storageKey and system theme support is required when isThemeSupported is false", () => {
      const result = getThemeProviderProps({
        ...fnArg,
        pathname: "/test",
        props: {
          ...fnArg.props,
          isThemeSupported: false,
        },
      });

      expect(result).toEqual({
        ...appThemeExpectedProps,
        storageKey: "forcedThemeKey",
        key: "forcedThemeKey",
        forcedTheme: "light",
        enableSystem: false,
      });
    });

    it("should not force theme when isThemeSupported is not explicitly set", () => {
      const result = getThemeProviderProps({
        ...fnArg,
        pathname: "/test",
        props: {
          ...fnArg.props,
          isThemeSupported: undefined,
        },
      });

      expect(result).toEqual({
        ...appThemeExpectedProps,
        forcedTheme: undefined,
        enableSystem: true,
      });
    });
  });

  describe("Booking Page Theme Support", () => {
    const bookingPageExpectedProps = {
      attribute: "class",
      nonce: "test-nonce",
      enableColorScheme: false,
    };

    it("should handle booking page theme", () => {
      const expectedStorageKey = "booking-theme:free";

      const result = getThemeProviderProps({
        ...fnArg,
        pathname: "/free/30min",
        props: {
          ...fnArg.props,
          isBookingPage: true,
        },
      });

      expect(result).toEqual({
        ...bookingPageExpectedProps,
        storageKey: expectedStorageKey,
        key: expectedStorageKey,
        forcedTheme: undefined,
        enableSystem: true,
      });
    });

    it("should handle team booking page theme configuration", () => {
      const result = getThemeProviderProps({
        ...fnArg,
        props: {
          ...fnArg.props,
          isBookingPage: true,
        },
        pathname: "/team/sales/30min",
      });

      expect(result.storageKey).toBe("booking-theme:sales");
    });
  });

  describe("Embed Mode Theme Support", () => {
    const embedProps = {
      ...fnArg,
      isEmbedMode: true,
    };

    const embedPageExpectedProps = {
      attribute: "class",
      nonce: "test-nonce",
      enableColorScheme: false,
      enableSystem: true,
      forcedTheme: undefined,
    };

    it("should handle embed mode with default theme", () => {
      const result = getThemeProviderProps({
        ...embedProps,
        embedNamespace: "ns",
        pathname: "/free",
      });
      const storageKey = "embed-theme-ns:free";
      expect(result).toEqual({
        ...embedPageExpectedProps,
        storageKey,
        key: storageKey,
      });
    });

    it("should handle embed mode with explicit theme. Must have theme name in storageKey so that different themes for different booking pages under same namespace also work", () => {
      const searchParams = new URLSearchParams();
      searchParams.set("theme", EmbedTheme.dark);
      const result = getThemeProviderProps({
        ...embedProps,
        searchParams: searchParams as unknown as ReadonlyURLSearchParams,
        pathname: "/free",
        embedNamespace: "ns",
      });

      const expectedStorageKey = "embed-theme-ns:free:dark";

      expect(result).toEqual({
        ...embedPageExpectedProps,
        storageKey: expectedStorageKey,
        key: expectedStorageKey,
      });
    });

    it("should not append theme suffix for auto theme as that is kind of default", () => {
      const searchParams = new URLSearchParams();
      searchParams.set("theme", EmbedTheme.auto);

      const result = getThemeProviderProps({
        ...embedProps,
        searchParams: searchParams as unknown as ReadonlyURLSearchParams,
        pathname: "/free",
        embedNamespace: "ns",
      });

      expect(result).toEqual({
        ...embedPageExpectedProps,
        storageKey: "embed-theme-ns:free",
        key: "embed-theme-ns:free",
      });
    });
  });
});

describe("getUniqueIdentifierForBookingPage", () => {
  describe("User Pages", () => {
    it.each([
      { path: "/test", expected: "test" },
      { path: "/test/anything", expected: "test" },
    ])("should return $expected for $path", ({ path, expected }) => {
      const result = getUniqueIdentifierForBookingPage({ pathname: path });
      expect(result).toBe(expected);
    });

    it("should return / for root path", () => {
      const result = getUniqueIdentifierForBookingPage({ pathname: "/" });
      expect(result).toBe("/");
    });
  });

  describe("Team Pages", () => {
    it.each([
      { path: "/team/test", expected: "test" },
      { path: "/team/test/anything", expected: "test" },
    ])("should return $expected for $path", ({ path, expected }) => {
      const result = getUniqueIdentifierForBookingPage({ pathname: path });
      expect(result).toBe(expected);
    });
  });

  describe("Private Booking Pages", () => {
    it.each([
      { path: "/d/private", expected: "private" },
      { path: "/d/private/anything", expected: "private" },
    ])("should return $expected for $path", ({ path, expected }) => {
      const result = getUniqueIdentifierForBookingPage({ pathname: path });
      expect(result).toBe(expected);
    });
  });

  describe("Dynamic Booking Pages", () => {
    it.each([
      { path: "/john+jane", expected: "john+jane" },
      { path: "/john+jane/", expected: "john+jane" },
      { path: "/john+jane/anything", expected: "john+jane" },
      { path: "/john%2bjane/anything", expected: "john%2bjane" },
    ])("should return $expected for $path", ({ path, expected }) => {
      const result = getUniqueIdentifierForBookingPage({ pathname: path });
      expect(result).toBe(expected);
    });
  });
});
