import { render, screen } from "@testing-library/svelte";
import { user } from "../setup-tests";
import ToastNotification from "./ToastNotification.test.svelte";
import ToastNotificationCustom from "./ToastNotificationCustom.test.svelte";
import ToastNotificationClose from "./ToastNotification.close.test.svelte";

describe("ToastNotification", () => {
  beforeEach(() => {
    vi.restoreAllMocks();
  });

  it("should render with default props", () => {
    render(ToastNotification);

    expect(screen.getByRole("alert")).toHaveClass(
      "bx--toast-notification--error",
    );
    expect(screen.getByText("Error")).toBeInTheDocument();
    expect(
      screen.getByText("An internal server error occurred."),
    ).toBeInTheDocument();
    expect(screen.getByText("2024-03-21 12:00:00")).toBeInTheDocument();
  });

  it("should handle different kinds", () => {
    const kinds = [
      "error",
      "info",
      "info-square",
      "success",
      "warning",
      "warning-alt",
    ] as const;

    kinds.forEach((kind) => {
      const { container } = render(ToastNotification, {
        props: { kind },
      });

      expect(
        container.querySelector(`.bx--toast-notification--${kind}`),
      ).toBeInTheDocument();
      container.remove();
    });
  });

  it("should handle low contrast variant", () => {
    render(ToastNotification, {
      props: { lowContrast: true },
    });

    expect(screen.getByRole("alert")).toHaveClass(
      "bx--toast-notification--low-contrast",
    );
  });

  it("should handle close button click", async () => {
    const consoleLog = vi.spyOn(console, "log");
    render(ToastNotification);

    await user.click(screen.getByRole("button"));

    expect(consoleLog).toHaveBeenCalledWith("close", { timeout: false });
    expect(screen.queryByRole("alert")).not.toBeInTheDocument();
  });

  it("should hide close button", () => {
    render(ToastNotification, {
      props: { hideCloseButton: true },
    });

    expect(
      screen.queryByLabelText("Close notification"),
    ).not.toBeInTheDocument();
  });

  it("should handle custom icon descriptions", () => {
    render(ToastNotification, {
      props: {
        statusIconDescription: "Custom status",
        closeButtonDescription: "Custom close",
      },
    });

    expect(screen.getByText("Custom status")).toBeInTheDocument();
    expect(screen.getByRole("button")).toHaveAttribute(
      "aria-label",
      "Custom close",
    );
  });

  it("should handle custom role", () => {
    render(ToastNotification, {
      props: { role: "status" },
    });

    expect(screen.getByRole("status")).toBeInTheDocument();
  });

  it("should handle timeout", async () => {
    vi.useFakeTimers();
    const consoleLog = vi.spyOn(console, "log");

    render(ToastNotification, { props: { timeout: 1000 } });

    expect(screen.getByRole("alert")).toBeInTheDocument();

    await vi.advanceTimersByTimeAsync(1000);

    expect(consoleLog).toHaveBeenCalledWith("close", { timeout: true });
    expect(screen.queryByRole("alert")).not.toBeInTheDocument();
    vi.useRealTimers();
  });

  it("should handle custom slots", () => {
    render(ToastNotificationCustom);

    const title = screen.getByText("Custom Title:");
    expect(title).not.toHaveClass("bx--toast-notification__title");
    expect(title.tagName).toBe("STRONG");

    const subtitle = screen.getByText("Custom subtitle content.");
    expect(subtitle).not.toHaveClass("bx--toast-notification__subtitle");
    expect(subtitle.tagName).toBe("STRONG");

    const caption = screen.getByText("Custom caption content.");
    expect(caption).not.toHaveClass("bx--toast-notification__caption");
    expect(caption.tagName).toBe("STRONG");
  });

  it("should handle full width", () => {
    render(ToastNotification, { props: { fullWidth: true } });

    const notification = screen.getByRole("alert");
    expect(notification).toHaveStyle({ width: "100%" });
  });

  it("should cleanup timeout on unmount", () => {
    vi.useFakeTimers();
    const clearTimeoutSpy = vi.spyOn(window, "clearTimeout");

    const { unmount } = render(ToastNotification, {
      props: { timeout: 1000 },
    });

    unmount();
    expect(clearTimeoutSpy).toHaveBeenCalled();
    vi.useRealTimers();
  });

  it("should prevent default close behavior", async () => {
    const consoleLog = vi.spyOn(console, "log");
    render(ToastNotificationClose);

    await user.click(screen.getByRole("button"));
    expect(consoleLog).toHaveBeenCalledWith("close", { timeout: false });
    expect(screen.getByRole("alert")).toBeInTheDocument();
  });
});
