/* @vitest-environment node */

import { describe, it, expect, vi, beforeEach } from "vitest";

vi.mock("sonner", () => {
	const api = {
		success: vi.fn(() => "toast-success-id"),
		error: vi.fn(() => "toast-error-id"),
		info: vi.fn(() => "toast-info-id"),
		warning: vi.fn(() => "toast-warning-id"),
		loading: vi.fn(() => "toast-loading-id"),
		dismiss: vi.fn(() => undefined),
	};

	return { toast: api };
});

import { toast } from "sonner";
import { ApiClientError } from "@/lib/frontend/apiClient";

import {
	notifySuccess,
	notifyError,
	notifyInfo,
	notifyWarning,
	notifyLoading,
	dismissToast,
	mapApiErrorToToast,
	notifyApiError,
} from "./toast.js";

describe("lib/frontend/ui/toast", () => {
	beforeEach(() => {
		vi.clearAllMocks();
	});

	it("notifySuccess calls toast.success with title + description", () => {
		const id = notifySuccess({
			title: "Gespeichert",
			description: "Änderungen wurden übernommen.",
		});

		expect(id).toBe("toast-success-id");
		expect(toast.success).toHaveBeenCalledWith("Gespeichert", {
			description: "Änderungen wurden übernommen.",
		});
	});

	it("notifyError calls toast.error", () => {
		const id = notifyError({ title: "Fehler", description: "Oh nein." });

		expect(id).toBe("toast-error-id");
		expect(toast.error).toHaveBeenCalledWith("Fehler", {
			description: "Oh nein.",
		});
	});

	it("notifyInfo / notifyWarning / notifyLoading forward correctly", () => {
		notifyInfo({ title: "Info", description: "Hinweis" });
		expect(toast.info).toHaveBeenCalledWith("Info", { description: "Hinweis" });

		notifyWarning({ title: "Warnung" });
		expect(toast.warning).toHaveBeenCalledWith("Warnung", {});

		notifyLoading({ title: "Lädt…" });
		expect(toast.loading).toHaveBeenCalledWith("Lädt…", {});
	});

	it("dismissToast forwards to toast.dismiss", () => {
		dismissToast("x");
		expect(toast.dismiss).toHaveBeenCalledWith("x");
	});

	it("mapApiErrorToToast maps network errors", () => {
		const err = new ApiClientError({
			status: 0,
			code: "CLIENT_NETWORK_ERROR",
			message: "Network error",
		});

		expect(mapApiErrorToToast(err)).toEqual({
			title: "Netzwerkfehler",
			description:
				"Bitte prüfen Sie Ihre Verbindung und versuchen Sie es erneut.",
		});
	});

	it("mapApiErrorToToast maps unauthenticated", () => {
		const err = new ApiClientError({
			status: 401,
			code: "AUTH_UNAUTHENTICATED",
			message: "Unauthorized",
		});

		expect(mapApiErrorToToast(err)).toEqual({
			title: "Sitzung abgelaufen",
			description: "Bitte melden Sie sich erneut an.",
		});
	});

	it("mapApiErrorToToast maps validation errors generically", () => {
		const err = new ApiClientError({
			status: 400,
			code: "VALIDATION_WEAK_PASSWORD",
			message: "Weak password",
		});

		expect(mapApiErrorToToast(err)).toEqual({
			title: "Ungültige Eingabe",
			description:
				"Bitte prüfen Sie Ihre Eingaben und versuchen Sie es erneut.",
		});
	});

	it("mapApiErrorToToast supports overrides by error code", () => {
		const err = new ApiClientError({
			status: 401,
			code: "AUTH_INVALID_CREDENTIALS",
			message: "Invalid credentials",
		});

		const mapped = mapApiErrorToToast(err, {
			overrides: {
				AUTH_INVALID_CREDENTIALS: {
					title: "Aktuelles Passwort ist falsch.",
					description: null,
				},
			},
		});

		expect(mapped).toEqual({
			title: "Aktuelles Passwort ist falsch.",
			description: null,
		});
	});

	it("notifyApiError uses toast.error with mapped copy", () => {
		const err = new ApiClientError({
			status: 0,
			code: "CLIENT_NETWORK_ERROR",
			message: "Network error",
		});

		const id = notifyApiError(err);

		expect(id).toBe("toast-error-id");
		expect(toast.error).toHaveBeenCalledWith("Netzwerkfehler", {
			description:
				"Bitte prüfen Sie Ihre Verbindung und versuchen Sie es erneut.",
		});
	});

	it("notifySuccess returns null and does not toast when title is missing", () => {
		const id = notifySuccess({ title: "   " });
		expect(id).toBe(null);
		expect(toast.success).not.toHaveBeenCalled();
	});
});
