import React from "react";
import { render, screen, waitFor, fireEvent } from "@testing-library/react";
import { jest } from "@jest/globals";

// Mock axios
const mockAxiosCreate = jest.fn(() => ({
  post: jest.fn(),
  get: jest.fn(),
}));

jest.unstable_mockModule("axios", () => ({
  __esModule: true,
  default: {
    create: mockAxiosCreate,
  },
}));

// Mock MSAL
const mockAcquireTokenSilent = jest.fn(() => Promise.resolve({ accessToken: "test-token" }));
const mockLogoutRedirect = jest.fn();

jest.unstable_mockModule("@azure/msal-react", () => ({
  __esModule: true,
  useMsal: () => ({
    instance: {
      acquireTokenSilent: mockAcquireTokenSilent,
      logoutRedirect: mockLogoutRedirect,
    },
    accounts: [{ username: "test@test.com" }],
  }),
}));

// Mock UserContext - with openRoleChangedPopup set to true
const mockLogout = jest.fn();
const mockSetOpenRoleChangedPopup = jest.fn();

jest.unstable_mockModule("../context/UserContext.js", () => ({
  __esModule: true,
  useUser: () => ({
    logout: mockLogout,
    user: { user_role_id: 1 },
    openRoleChangedPopup: true, // Set to true to test popup visibility
    setOpenRoleChangedPopup: mockSetOpenRoleChangedPopup,
  }),
}));

// Mock useTokenExpiryMonitor
jest.unstable_mockModule("../hooks/useTokenExpiryMonitor.js", () => ({
  __esModule: true,
  useTokenExpiryMonitor: () => ({
    setDialog: jest.fn(),
  }),
}));

// Mock RoleChangedPopup with onLogout handler
jest.unstable_mockModule("../components/RoleChangedPopup.js", () => ({
  __esModule: true,
  default: ({ open, onLogout, message }) => (
    open ? (
      <div data-testid="role-changed-popup">
        <span data-testid="popup-message">{message}</span>
        <button data-testid="logout-btn" onClick={onLogout}>Logout</button>
      </div>
    ) : null
  ),
}));

// Import after mocks
const { default: useApiService } = await import("../services/apiService.js");

// Test component that uses the hook
function TestComponent({ endpoint, data }) {
  const { postApi, getApi, RoleChangedPopupElement } = useApiService();
  const [result, setResult] = React.useState(null);
  const [error, setError] = React.useState(null);

  const handlePost = async () => {
    try {
      const res = await postApi(endpoint, data);
      setResult(res);
    } catch (e) {
      setError(e);
    }
  };

  const handleGet = async () => {
    try {
      const res = await getApi(endpoint);
      setResult(res);
    } catch (e) {
      setError(e);
    }
  };

  return (
    <div>
      <button onClick={handlePost} data-testid="post-btn">Post</button>
      <button onClick={handleGet} data-testid="get-btn">Get</button>
      {result && <div data-testid="result">{JSON.stringify(result)}</div>}
      {error && <div data-testid="error">Error</div>}
      {RoleChangedPopupElement}
    </div>
  );
}

describe("apiService hook - Role Changed Popup", () => {
  beforeEach(() => {
    jest.clearAllMocks();
    localStorage.clear();
  });

  it("renders RoleChangedPopup when openRoleChangedPopup is true", () => {
    render(<TestComponent endpoint="/test" data={{}} />);
    expect(screen.getByTestId("role-changed-popup")).toBeInTheDocument();
  });

  it("displays error message from localStorage in popup", () => {
    localStorage.setItem("ErrorMessage", "Role Changed. Please Re-Login");
    render(<TestComponent endpoint="/test" data={{}} />);
    expect(screen.getByTestId("role-changed-popup")).toBeInTheDocument();
  });

  it("calls handleLogout when logout button is clicked", async () => {
    render(<TestComponent endpoint="/test" data={{}} />);
    
    const logoutBtn = screen.getByTestId("logout-btn");
    fireEvent.click(logoutBtn);

    await waitFor(() => {
      expect(mockSetOpenRoleChangedPopup).toHaveBeenCalledWith(false);
    });
    await waitFor(() => {
      expect(mockLogout).toHaveBeenCalled();
    });
    await waitFor(() => {
      expect(mockLogoutRedirect).toHaveBeenCalled();
    });
  });

  it("handles 498 error and triggers role changed popup flow", async () => {
    const mockPost = jest.fn(() => Promise.reject({
      response: {
        status: 498,
        data: { IsSuccess: false, Message: "Role Changed. Please Re-Login" }
      }
    }));
    mockAxiosCreate.mockReturnValueOnce({
      post: mockPost,
      get: jest.fn(),
    });

    render(<TestComponent endpoint="/test" data={{ name: "test" }} />);
    
    const postBtn = screen.getByTestId("post-btn");
    fireEvent.click(postBtn);

    await waitFor(() => {
      expect(screen.getByTestId("role-changed-popup")).toBeInTheDocument();
    });
  });

  it("handles 499 error for deleted user", async () => {
    const mockPost = jest.fn(() => Promise.reject({
      response: {
        status: 499,
        data: { IsSuccess: false, Message: "User has been deleted. Please contact the administrator." }
      }
    }));
    mockAxiosCreate.mockReturnValueOnce({
      post: mockPost,
      get: jest.fn(),
    });

    render(<TestComponent endpoint="/test" data={{ name: "test" }} />);
    
    const postBtn = screen.getByTestId("post-btn");
    fireEvent.click(postBtn);

    await waitFor(() => {
      expect(screen.getByTestId("role-changed-popup")).toBeInTheDocument();
    });
  });

  it("handles 497 error for inactive user", async () => {
    const mockPost = jest.fn(() => Promise.reject({
      response: {
        status: 497,
        data: { IsSuccess: false, Message: "User Status changed to Inactive. Please contact the administrator." }
      }
    }));
    mockAxiosCreate.mockReturnValueOnce({
      post: mockPost,
      get: jest.fn(),
    });

    render(<TestComponent endpoint="/test" data={{ name: "test" }} />);
    
    const postBtn = screen.getByTestId("post-btn");
    fireEvent.click(postBtn);

    await waitFor(() => {
      expect(screen.getByTestId("role-changed-popup")).toBeInTheDocument();
    });
  });

  it("stores error message in localStorage when role changes", async () => {
    const mockPost = jest.fn(() => Promise.reject({
      response: {
        status: 498,
        data: { IsSuccess: false, Message: "Role Changed. Please Re-Login" }
      }
    }));
    mockAxiosCreate.mockReturnValueOnce({
      post: mockPost,
      get: jest.fn(),
    });

    render(<TestComponent endpoint="/test" data={{ name: "test" }} />);
    
    const postBtn = screen.getByTestId("post-btn");
    fireEvent.click(postBtn);

    await waitFor(() => {
      expect(screen.getByTestId("post-btn")).toBeInTheDocument();
    });
  });

  it("handles logout redirect after clicking logout button", async () => {
    render(<TestComponent endpoint="/test" data={{}} />);
    
    const logoutBtn = screen.getByTestId("logout-btn");
    fireEvent.click(logoutBtn);

    await waitFor(() => {
      expect(mockLogoutRedirect).toHaveBeenCalled();
    });
  });

  it("sets openRoleChangedPopup to false on logout", async () => {
    render(<TestComponent endpoint="/test" data={{}} />);
    
    const logoutBtn = screen.getByTestId("logout-btn");
    fireEvent.click(logoutBtn);

    await waitFor(() => {
      expect(mockSetOpenRoleChangedPopup).toHaveBeenCalledWith(false);
    });
  });
});
