import React from "react";
import { render, screen, waitFor } from "@testing-library/react";
import { toast } from "react-toastify";
import NotificationProvider, { notify } from "../../context/NotificationProvider";
import { SSEContext } from "../../context/SSEContext";
import { AuthContext } from "../../context/AuthContext";

// Mock axios to prevent import errors
jest.mock("axios");

// Mock react-toastify
jest.mock("react-toastify", () => ({
  toast: {
    success: jest.fn(),
    error: jest.fn(),
    info: jest.fn(),
    warning: jest.fn(),
    dismiss: jest.fn(),
  },
}));

describe("NotificationProvider", () => {
  let mockSSEContext;
  let mockAuthContext;

  beforeEach(() => {
    jest.clearAllMocks();

    mockSSEContext = {
      connected: true,
      notifications: [],
      on: jest.fn(),
      off: jest.fn(),
      subscribe: jest.fn().mockResolvedValue({ subscribed: [] }),
      unsubscribe: jest.fn().mockResolvedValue({ unsubscribed: [] }),
      clearNotification: jest.fn(),
      clearAllNotifications: jest.fn(),
    };

    mockAuthContext = {
      auth: {
        isAuthenticated: true,
        user: { id: "user123", name: "Test User" },
      },
    };
  });

  const renderWithProviders = (children) => {
    return render(
      <AuthContext.Provider value={mockAuthContext}>
        <SSEContext.Provider value={mockSSEContext}>
          <NotificationProvider>{children}</NotificationProvider>
        </SSEContext.Provider>
      </AuthContext.Provider>
    );
  };

  test("renders children correctly", () => {
    renderWithProviders(<div>Test Content</div>);
    expect(screen.getByText("Test Content")).toBeInTheDocument();
  });

  test("subscribes to custom events via context", () => {
    renderWithProviders(<div>Test</div>);

    // Verify custom event listeners were registered via context
    expect(mockSSEContext.on).toHaveBeenCalledWith("eventUpdate", expect.any(Function));
    expect(mockSSEContext.on).toHaveBeenCalledWith("taskUpdate", expect.any(Function));
    expect(mockSSEContext.on).toHaveBeenCalledWith("streetUpdate", expect.any(Function));
    expect(mockSSEContext.on).toHaveBeenCalledWith("achievementUnlocked", expect.any(Function));
    expect(mockSSEContext.on).toHaveBeenCalledWith("newPost", expect.any(Function));
    expect(mockSSEContext.on).toHaveBeenCalledWith("newComment", expect.any(Function));
    expect(mockSSEContext.on).toHaveBeenCalledWith("notification", expect.any(Function));
  });

  test("cleans up event listeners on unmount", () => {
    const { unmount } = renderWithProviders(<div>Test</div>);

    unmount();

    // Verify custom event listeners were removed via context
    expect(mockSSEContext.off).toHaveBeenCalledWith("eventUpdate", expect.any(Function));
    expect(mockSSEContext.off).toHaveBeenCalledWith("taskUpdate", expect.any(Function));
    expect(mockSSEContext.off).toHaveBeenCalledWith("streetUpdate", expect.any(Function));
    expect(mockSSEContext.off).toHaveBeenCalledWith("achievementUnlocked", expect.any(Function));
    expect(mockSSEContext.off).toHaveBeenCalledWith("newPost", expect.any(Function));
    expect(mockSSEContext.off).toHaveBeenCalledWith("newComment", expect.any(Function));
    expect(mockSSEContext.off).toHaveBeenCalledWith("notification", expect.any(Function));
  });

  test("does not subscribe when not connected", () => {
    mockSSEContext.connected = false;

    renderWithProviders(<div>Test</div>);

    // Event listeners should not be registered when not connected
    expect(mockSSEContext.on).not.toHaveBeenCalled();
  });
});

describe("notify utility", () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  test("notify.success calls toast.success", () => {
    notify.success("Test message");
    expect(toast.success).toHaveBeenCalledWith("Test message", {});
  });

  test("notify.error calls toast.error", () => {
    notify.error("Error message");
    expect(toast.error).toHaveBeenCalledWith("Error message", {});
  });

  test("notify.info calls toast.info", () => {
    notify.info("Info message");
    expect(toast.info).toHaveBeenCalledWith("Info message", {});
  });

  test("notify.warning calls toast.warning", () => {
    notify.warning("Warning message");
    expect(toast.warning).toHaveBeenCalledWith("Warning message", {});
  });

  test("notify.success accepts custom options", () => {
    const options = { autoClose: 3000, position: "bottom-right" };
    notify.success("Test", options);
    expect(toast.success).toHaveBeenCalledWith("Test", options);
  });

  test("notify.dismiss calls toast.dismiss with toastId", () => {
    notify.dismiss("test-toast-id");
    expect(toast.dismiss).toHaveBeenCalledWith("test-toast-id");
  });

  test("notify.dismissAll calls toast.dismiss without arguments", () => {
    notify.dismissAll();
    expect(toast.dismiss).toHaveBeenCalledWith();
  });
});
