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

// --------------------
// Mock Functions
// --------------------

const mockPostApi = jest.fn();
const mockGetUserData = jest.fn();
const mockGetUsersTable = jest.fn();

// --------------------
// Mock Modules
// --------------------

jest.unstable_mockModule("../services/apiService.js", () => ({
  __esModule: true,
  default: () => ({
    postApi: mockPostApi,
  }),
}));

jest.unstable_mockModule("../context/UserContext.js", () => ({
  useUser: () => ({
    user: { user_email: "admin@test.com" },
  }),
}));

jest.unstable_mockModule("@mui/material", () => ({
  Popover: ({ children, open }) => (open ? <div>{children}</div> : null),
  Typography: ({ children }) => <div>{children}</div>,
}));

jest.unstable_mockModule("@mui/icons-material/", () => ({
  MoreVert: () => <span data-testid="more-icon" />,
}));

jest.unstable_mockModule("rsuite", () => ({
  Loader: () => <div data-testid="loader" />,
}));

jest.unstable_mockModule("./EditPopup.js", () => ({
  __esModule: true,
  default: () => <div data-testid="edit-popup">Edit Popup</div>,
}));

jest.unstable_mockModule("../common/ConsentPopup.js", () => ({
  __esModule: true,
  default: ({ title, onAccept, onClose }) => (
    <div>
      <div>{title}</div>
      <button data-testid="confirm-btn" onClick={onAccept}>
        Confirm
      </button>
      <button data-testid="cancel-btn" onClick={onClose}>
        Cancel
      </button>
    </div>
  ),
}));

jest.unstable_mockModule("../constants/userConstants.js", () => ({
  consentType: { Consent: "CONSENT" },
  userStatus: {
    Active: { key: "ACTIVE" },
    Deactive: { key: "DEACTIVE" },
    Deleted: { key: "DELETED" },
  },
}));

jest.unstable_mockModule("../constants/apiEndPoints.js", () => ({
  UserActiveInactive: "/api/user/status",
}));

// Load component after mocks
const ActionBtn = (await import("./ActionBtn.js")).default;

// --------------------
// Test Data
// --------------------

const defaultUser = {
  user_id: "1",
  user_email: "user@test.com",
  user_status: "ACTIVE",
  user_first_name: "John",
  user_last_name: "Doe",
  user_role_id: "admin",
};

describe("ActionBtn Component", () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

 
  it("renders action button", () => {
    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    expect(screen.getByLabelText("More actions")).toBeInTheDocument();
  });


  it("opens popover when clicking more actions", () => {
    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));

    expect(screen.getByText("Edit")).toBeInTheDocument();
    expect(screen.getByText("Delete")).toBeInTheDocument();
  });

  
  it("opens edit popup when Edit is clicked", () => {
    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    fireEvent.click(screen.getByText("Edit"));

    expect(screen.getByTestId("edit-popup")).toBeInTheDocument();
  });

  
  it("shows deactivate confirmation popup", () => {
    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    fireEvent.click(screen.getByText("Deactive"));

    expect(screen.getByText(/Confirm Deactivation/i)).toBeInTheDocument();
  });

  it("calls API when deactivate confirmed", async () => {
    mockPostApi.mockResolvedValueOnce({});

    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    fireEvent.click(screen.getByText("Deactive"));
    fireEvent.click(screen.getByTestId("confirm-btn"));

    await waitFor(() => {
      expect(mockPostApi).toHaveBeenCalledWith(
        "/api/user/status",
        expect.objectContaining({
          UserId: "1",
          UserStatus: "DEACTIVE",
        })
      );
    });

    expect(mockGetUserData).toHaveBeenCalled();
  });

 
  it("shows delete confirmation popup", () => {
    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    fireEvent.click(screen.getByText("Delete"));

    expect(screen.getByText("Delete User Confirmation")).toBeInTheDocument();
  });

  it("calls API when delete confirmed", async () => {
    mockPostApi.mockResolvedValueOnce({});

    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    fireEvent.click(screen.getByText("Delete"));
    fireEvent.click(screen.getByTestId("confirm-btn"));

    await waitFor(() => {
      expect(mockPostApi).toHaveBeenCalledWith(
        "/api/user/status",
        expect.objectContaining({
          UserId: "1",
          Isdelete: true,
          UserStatus: "DELETED",
        })
      );
    });

    expect(mockGetUsersTable).toHaveBeenCalled();
  });

 
  it("shows loader while API is loading", async () => {
    let resolveApi;
    mockPostApi.mockImplementationOnce(
      () => new Promise((resolve) => (resolveApi = resolve))
    );

    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    fireEvent.click(screen.getByText("Delete"));
    fireEvent.click(screen.getByTestId("confirm-btn"));

    expect(screen.getByTestId("loader")).toBeInTheDocument();

    resolveApi({});

    await waitFor(() => {
      expect(screen.queryByTestId("loader")).not.toBeInTheDocument();
    });
  });

  // Additional tests to cover more lines

  // Test handleInputChange (lines 34-35)
  it("handles input change in edit popup", async () => {
    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    fireEvent.click(screen.getByText("Edit"));

    expect(screen.getByTestId("edit-popup")).toBeInTheDocument();
  });

  // Test handleClose (line 55)
  it("closes popover when handleClose is called", () => {
    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    expect(screen.getByText("Edit")).toBeInTheDocument();
  });

  // Test handleCancel (line 76)
  it("closes confirmation popup when cancel is clicked", () => {
    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    fireEvent.click(screen.getByText("Deactive"));
    fireEvent.click(screen.getByTestId("cancel-btn"));

    // The confirmation popup should be closed
    expect(screen.queryByText(/Confirm Deactivation/i)).not.toBeInTheDocument();
  });

  // Test with deactive user (Re-Active button - line 62)
  it("shows Re-Active button for deactive users", () => {
    const deactiveUser = {
      ...defaultUser,
      user_status: "DEACTIVE",
    };

    render(
      <ActionBtn
        userData={deactiveUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    expect(screen.getByText("Re-Active")).toBeInTheDocument();
  });

  // Test handleActiveDelete with Re-Active action
  it("calls API with Active status when re-activating user", async () => {
    mockPostApi.mockResolvedValueOnce({});

    const deactiveUser = {
      ...defaultUser,
      user_status: "DEACTIVE",
    };

    render(
      <ActionBtn
        userData={deactiveUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    fireEvent.click(screen.getByText("Re-Active"));
    fireEvent.click(screen.getByTestId("confirm-btn"));

    await waitFor(() => {
      expect(mockPostApi).toHaveBeenCalledWith(
        "/api/user/status",
        expect.objectContaining({
          UserId: "1",
          UserStatus: "ACTIVE",
        })
      );
    });

    expect(mockGetUserData).toHaveBeenCalled();
  });

  // Test API error handling (line 55)
  it("handles API error gracefully during deactivation", async () => {
    mockPostApi.mockRejectedValueOnce(new Error("API Error"));
    const consoleSpy = jest.spyOn(console, "error").mockImplementation(() => {});

    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    fireEvent.click(screen.getByText("Deactive"));
    fireEvent.click(screen.getByTestId("confirm-btn"));

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

    consoleSpy.mockRestore();
  });

  // Test API error handling for delete (line 102)
  it("handles API error gracefully during deletion", async () => {
    mockPostApi.mockRejectedValueOnce(new Error("API Error"));
    const consoleSpy = jest.spyOn(console, "error").mockImplementation(() => {});

    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    fireEvent.click(screen.getByText("Delete"));
    fireEvent.click(screen.getByTestId("confirm-btn"));

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

    consoleSpy.mockRestore();
  });

  // Test handleCloseConsetPopup (lines 87-88)
  it("closes consent popup when cancel is clicked", () => {
    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    fireEvent.click(screen.getByText("Delete"));
    fireEvent.click(screen.getByTestId("cancel-btn"));

    // Consent popup should be closed
    expect(screen.queryByText("Delete User Confirmation")).not.toBeInTheDocument();
  });

  // Test with missing userData fields
  it("handles missing userData fields gracefully", () => {
    const incompleteUser = {
      user_id: "2",
      user_email: "incomplete@test.com",
      user_status: "ACTIVE",
    };

    render(
      <ActionBtn
        userData={incompleteUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    expect(screen.getByText("Edit")).toBeInTheDocument();
  });

  // Test when user and userData have same email (no deactive button)
  it("does not show deactive button when user and userData have same email", () => {
    const sameEmailUser = {
      ...defaultUser,
      user_email: "admin@test.com", // Same as mocked user email
    };

    render(
      <ActionBtn
        userData={sameEmailUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    expect(screen.queryByText("Deactive")).not.toBeInTheDocument();
    expect(screen.queryByText("Re-Active")).not.toBeInTheDocument();
  });

  // Test with deleted user (no delete button)
  it("does not show delete button for already deleted users", () => {
    const deletedUser = {
      ...defaultUser,
      user_status: "DELETED",
    };

    render(
      <ActionBtn
        userData={deletedUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    expect(screen.queryByText("Delete")).not.toBeInTheDocument();
  });

  // Test keyboard navigation for Edit button (line 157-159)
  it("handles keyboard Enter press on Edit button", () => {
    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    const editButton = screen.getByText("Edit");
    fireEvent.keyDown(editButton, { key: "Enter" });

    expect(screen.getByTestId("edit-popup")).toBeInTheDocument();
  });

  // Test keyboard navigation for Edit button with Space key
  it("handles keyboard Space press on Edit button", () => {
    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    const editButton = screen.getByText("Edit");
    fireEvent.keyDown(editButton, { key: " " });

    expect(screen.getByTestId("edit-popup")).toBeInTheDocument();
  });

  // Test keyboard navigation for Deactive button
  it("handles keyboard Enter press on Deactive button", () => {
    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    const deactiveButton = screen.getByText("Deactive");
    fireEvent.keyDown(deactiveButton, { key: "Enter" });

    expect(screen.getByText(/Confirm Deactivation/i)).toBeInTheDocument();
  });

  // Test keyboard navigation for Delete button
  it("handles keyboard Enter press on Delete button", () => {
    render(
      <ActionBtn
        userData={defaultUser}
        getUserData={mockGetUserData}
        getUsersTable={mockGetUsersTable}
      />
    );

    fireEvent.click(screen.getByLabelText("More actions"));
    const deleteButton = screen.getByText("Delete");
    fireEvent.keyDown(deleteButton, { key: "Enter" });

    expect(screen.getByText("Delete User Confirmation")).toBeInTheDocument();
  });
});