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



const mockPostApi = jest.fn();
const mockToastSuccess = jest.fn();
const mockToastError = jest.fn();
const mockToastWarning = jest.fn();

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

jest.unstable_mockModule("react-toastify", () => ({
  toast: {
    success: mockToastSuccess,
    error: mockToastError,
    warning: mockToastWarning,
  },
}));

jest.unstable_mockModule("./CreateEditRoleDialog.js", () => ({
  CreateEditRoleDialog: (props) => (
    <div data-testid="create-edit-dialog">
      <button onClick={props.handleRoleSave}>Save Role</button>
      <button onClick={props.handlePermissionSave}>Save Permissions</button>
    </div>
  ),
}));

jest.unstable_mockModule("../../common/ConsentPopup.js", () => ({
  __esModule: true,
  default: (props) => (
    <div data-testid="consent-popup">
      <button onClick={props.onAccept}>Confirm Delete</button>
    </div>
  ),
}));

const ManageRolesPermissionsPopup = (await import("./ManageRolesPermissionsPopup.js")).default;



const defaultProps = {
  open: true,
  onClose: jest.fn(),
  onSave: jest.fn().mockResolvedValue(1),
  getRoleData: jest.fn().mockResolvedValue([]),
  roleData: null,
  allModules: [
    { Id: 1, Name: "Dashboard" },
    { Id: 2, Name: "Users" },
  ],
  actionType: "addEdit",
  setActionType: jest.fn(),
  editRoleData: { Role_Id: 1, RoleName: "Admin" },
  getRoleTable: jest.fn(),
  getAllRoles: jest.fn(),
  allRoles: [],
};


describe("ManageRolesPermissionsPopup", () => {
  beforeEach(() => {
    jest.clearAllMocks();
    mockPostApi.mockResolvedValue({
      Records: [{ Message: "Role deleted successfully!" }],
    });
  });

  test("renders nothing when open is false", () => {
    const { container } = render(
      <ManageRolesPermissionsPopup {...defaultProps} open={false} />
    );
    expect(container).toBeEmptyDOMElement();
  });

  test("renders CreateEditRoleDialog when actionType is addEdit", () => {
    render(<ManageRolesPermissionsPopup {...defaultProps} />);
    expect(screen.getByTestId("create-edit-dialog")).toBeInTheDocument();
  });

  test("renders DeletePopup when actionType is delete", () => {
    render(
      <ManageRolesPermissionsPopup
        {...defaultProps}
        actionType="delete"
      />
    );

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

  test("shows validation warning when role name is invalid", async () => {
    render(<ManageRolesPermissionsPopup {...defaultProps} />);

    fireEvent.click(screen.getByText("Save Role"));

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

  test("calls onSave and shows success when saving role successfully", async () => {
    const validProps = {
      ...defaultProps,
      roleData: { RoleId: 1, RoleName: "Manager", ViewType: "1" },
      getRoleData: jest.fn().mockResolvedValue([
        { ViewType: "1", RoleName: "Manager" },
      ]),
    };

    render(<ManageRolesPermissionsPopup {...validProps} />);

    fireEvent.click(screen.getByText("Save Role"));

    await waitFor(() => {
      expect(validProps.onSave).toHaveBeenCalled();
    }, { timeout: 3000 });

    await waitFor(() => {
      expect(validProps.getRoleData).toHaveBeenCalled();
    }, { timeout: 3000 });
  });

  test("shows error and closes when role save returns falsy", async () => {
    const props = {
      ...defaultProps,
      onSave: jest.fn().mockResolvedValue(null),
      roleData: { RoleId: 1, RoleName: "Manager", ViewType: "1" },
    };

    render(<ManageRolesPermissionsPopup {...props} />);

    fireEvent.click(screen.getByText("Save Role"));

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

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

  test("calls permission save handler", async () => {
    render(<ManageRolesPermissionsPopup {...defaultProps} />);

    fireEvent.click(screen.getByText("Save Permissions"));

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

  test("shows success and closes on permission save", async () => {
    const props = {
      ...defaultProps,
      onSave: jest.fn().mockResolvedValue(true),
      getRoleData: jest.fn().mockResolvedValue([
        { ViewType: "1", RoleName: "Manager" },
      ]),
      roleData: { RoleId: 1, RoleName: "Manager", ViewType: "1" },
    };

    render(<ManageRolesPermissionsPopup {...props} />);

    fireEvent.click(screen.getByText("Save Permissions"));

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

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

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

  test("shows error when permission save fails", async () => {
    const props = {
      ...defaultProps,
      onSave: jest.fn().mockRejectedValue(new Error("Save failed")),
      roleData: { RoleId: 1, RoleName: "Manager", ViewType: "1" },
    };

    render(<ManageRolesPermissionsPopup {...props} />);

    fireEvent.click(screen.getByText("Save Permissions"));

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

    expect(props.onClose).not.toHaveBeenCalled();
  });

  test("shows error toast when getRoleData fails on mount", async () => {
    const consoleSpy = jest.spyOn(console, "error").mockImplementation(() => {});
    const props = {
      ...defaultProps,
      getRoleData: jest.fn().mockRejectedValue(new Error("Fetch failed")),
      roleData: { RoleId: 1, RoleName: "Manager", ViewType: "1" },
    };

    render(<ManageRolesPermissionsPopup {...props} />);

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

    consoleSpy.mockRestore();
  });

  test("calls delete API on confirm", async () => {
    render(
      <ManageRolesPermissionsPopup
        {...defaultProps}
        actionType="delete"
      />
    );

    fireEvent.click(screen.getByText("Confirm Delete"));

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

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

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

  test("handles API error gracefully on delete", async () => {
    mockPostApi.mockRejectedValueOnce(new Error("API error"));

    render(
      <ManageRolesPermissionsPopup
        {...defaultProps}
        actionType="delete"
      />
    );

    fireEvent.click(screen.getByText("Confirm Delete"));

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

    expect(mockToastError).not.toHaveBeenCalled();
  });
});