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

let mockPermissions = [];
let nanoidCounter = 0;

jest.unstable_mockModule("../context/UserContext.js", () => ({
  __esModule: true,
  useUser: () => ({ permissions: mockPermissions }),
}));

jest.unstable_mockModule("react-router-dom", () => ({
  __esModule: true,
  Link: ({ to, children, ...rest }) => (
    <a href={to} {...rest}>
      {children}
    </a>
  ),
}));

jest.unstable_mockModule("nanoid", () => ({
  __esModule: true,
  nanoid: () => {
    nanoidCounter += 1;
    return `row-${nanoidCounter}`;
  },
}));

jest.unstable_mockModule("react-lazy-load-image-component", () => ({
  __esModule: true,
  default: {
    LazyLoadImage: ({ alt, src, onClick }) => (
      <button type="button" onClick={onClick} aria-label={alt}>
        <img alt={alt} src={src} />
      </button>
    ),
  },
}));

jest.unstable_mockModule("@mui/icons-material", () => ({
  __esModule: true,
  FirstPage: () => <span>FirstPage</span>,
  LastPage: () => <span>LastPage</span>,
  Close: () => <span>Close</span>,
}));

jest.unstable_mockModule("@mui/material", () => ({
  __esModule: true,
  TextField: ({ value, onChange, onKeyDown, placeholder, inputProps, ...rest }) => (
    <input
      value={value}
      onChange={onChange}
      onKeyDown={onKeyDown}
      placeholder={placeholder}
      {...inputProps}
      {...rest}
    />
  ),
  Button: ({ disabled, onClick, children, ...rest }) => (
    <button type="button" disabled={disabled} onClick={onClick} {...rest}>
      {children}
    </button>
  ),
  Paper: ({ children, ...rest }) => <div {...rest}>{children}</div>,
  TablePagination: ({ count, page, rowsPerPage, labelDisplayedRows }) => (
    <div data-testid="table-pagination">
      {labelDisplayedRows
        ? labelDisplayedRows({
            from: count === 0 ? 0 : page * rowsPerPage + 1,
            to: Math.min(count, (page + 1) * rowsPerPage),
            count,
          })
        : null}
    </div>
  ),
  IconButton: ({ disabled, onClick, children, ...rest }) => (
    <button type="button" disabled={disabled} onClick={onClick} {...rest}>
      {children}
    </button>
  ),
  Modal: ({ open, children }) =>
    open ? <div data-testid="modal">{children}</div> : null,
  Box: ({ children }) => <div data-testid="box">{children}</div>,
}));

jest.unstable_mockModule("@mui/x-data-grid", () => ({
  __esModule: true,
  useGridApiRef: () => ({ current: { scrollToIndexes: jest.fn() } }),
  DataGrid: ({ columns = [], rows = [], localeText, onSortModelChange }) => {
    const sortedRowIds = rows.map((row) => row.id);
    const api = { getSortedRowIds: () => sortedRowIds };

    const sortButtons = [];
    for (const col of columns) {
      sortButtons.push(
        <button
          key={col.field}
          type="button"
          data-testid={`sort-${col.field}`}
          onClick={() => onSortModelChange?.([{ field: col.field, sort: "asc" }])}
        >
          Sort {col.field}
        </button>
      );
    }

    const rowNodes = [];
    for (const row of rows) {
      const cellNodes = [];
      for (const col of columns) {
        const renderedValue = col.renderCell
          ? col.renderCell({ id: row.id, row, api })
          : row[col.field];
        cellNodes.push(
          <span key={col.field} data-testid={`cell-${row.id}-${col.field}`}>
            {renderedValue}
          </span>
        );
      }

      rowNodes.push(
        <div key={row.id} data-testid={`row-${row.id}`}>
          {cellNodes}
        </div>
      );
    }

    return (
      <div data-testid="datagrid">
        <div>
          {sortButtons}
          <button
            type="button"
            data-testid="clear-sort"
            onClick={() => onSortModelChange?.([])}
          >
            Clear Sort
          </button>
        </div>
        {rows.length === 0 ? (
          <div>{localeText?.noRowsLabel ?? "No rows"}</div>
        ) : (
          <div>{rowNodes}</div>
        )}
      </div>
    );
  },
}));

jest.unstable_mockModule("../utils/secondToTime.js", () => ({
  __esModule: true,
  default: (value) => `time:${value}`,
}));

jest.unstable_mockModule("../utils/dateFormat.js", () => ({
  __esModule: true,
  default: (value) => `utc:${value}`,
}));

jest.unstable_mockModule("../components/ActionBtn.js", () => ({
  __esModule: true,
  default: () => <div data-testid="action-btn" />,
}));

jest.unstable_mockModule("../pages/ActionForPermission.js", () => ({
  __esModule: true,
  default: () => <div data-testid="permission-action" />,
}));

jest.unstable_mockModule("./PopupForAuditLogs.js", () => ({
  __esModule: true,
  default: ({ togglePopup }) => (
    <div data-testid="audit-popup">
      <button type="button" onClick={togglePopup}>
        Close Popup
      </button>
    </div>
  ),
}));

describe("CommonTable", () => {
  let CommonTable;

  beforeAll(async () => {
    ({ default: CommonTable } = await import("./CommonTable.js"));
  });

  beforeEach(() => {
    nanoidCounter = 0;
    mockPermissions = [];
  });

  const baseFilters = {
    PageNumber: 1,
    PageSize: 50,
    SortColumn: null,
    SortOrder: null,
    SearchText: "",
  };

  test("shows no-rows label and hides pagination when empty", () => {
    render(
      <CommonTable
        title="Users"
        component="Test"
        data={{ Records: [], CurrentPage: 1, TotalRecords: 0, PageSize: 50 }}
        columns={[{ field: "name", headerName: "Name" }]}
        filters={baseFilters}
        onChange={jest.fn()}
      />
    );

    expect(screen.getByText("No data available")).toBeInTheDocument();
    expect(screen.queryByPlaceholderText("Page No")).not.toBeInTheDocument();
  });

  test("supports sorting (including ManageUser shape) and clearing sort", () => {
    const onChange = jest.fn();
    const togglePopup = jest.fn();

    render(
      <CommonTable
        title="Users"
        component="ManageUser"
        data={{
          Records: [
            {
              EmpCode: "E1",
              EmployeeName: "Alice",
              emp_code: "E1",
              application_name: "AppX",
              application_count: 2,
            },
          ],
          CurrentPage: 1,
          TotalRecords: 1,
          PageSize: 50,
        }}
        columns={[
          { field: "EmpCode", headerName: "EmpCode" },
          { field: "application_name", headerName: "App" },
        ]}
        filters={baseFilters}
        onChange={onChange}
        togglePopup={togglePopup}
      />
    );

    fireEvent.click(screen.getByTestId("sort-EmpCode"));
    expect(onChange).toHaveBeenCalled();
    expect(onChange.mock.calls.at(-1)[0]).toEqual(
      expect.objectContaining({
        Filter: expect.objectContaining({
          SortColumn: "EmployeeName",
          SortDirection: "ASC",
          FilterColumn: null,
          FilterValue: null,
        }),
      })
    );

    fireEvent.click(screen.getByTestId("clear-sort"));
    expect(onChange.mock.calls.at(-1)[0]).toEqual(
      expect.objectContaining({
        SortColumn: null,
        SortOrder: null,
      })
    );
  });

  test("handles jump-to-page, last-page click, and disables Go for invalid page", () => {
    const onChange = jest.fn();

    render(
      <CommonTable
        title="Users"
        component="Test"
        data={{
          Records: [{ EmpCode: "E1", EmployeeName: "Alice" }],
          CurrentPage: 1,
          TotalRecords: 120,
          PageSize: 50,
        }}
        columns={[{ field: "EmpCode", headerName: "EmpCode" }]}
        filters={baseFilters}
        onChange={onChange}
      />
    );

    const pageInput = screen.getByPlaceholderText("Page No");

    fireEvent.change(pageInput, { target: { value: "0" } });
    const goButton = screen.getByRole("button", { name: "Go" });
    expect(goButton).toBeDisabled();

    fireEvent.change(pageInput, { target: { value: "2" } });
    expect(goButton).not.toBeDisabled();
    fireEvent.click(goButton);

    expect(onChange).toHaveBeenCalledWith(
      expect.objectContaining({ PageNumber: 2, PageSize: 50 })
    );

    fireEvent.click(screen.getByText("LastPage"));
    expect(onChange).toHaveBeenLastCalledWith(
      expect.objectContaining({ PageNumber: 3, PageSize: 50 })
    );
  });

  test("opens/closes screenshot modal and renders audit-log popup for operation_type", () => {
    const onChange = jest.fn();
    mockPermissions = [
      { Path: "/user-profile", Permission_Id: "1" },
      { Path: "/other", Permission_Id: "3" },
    ];

    render(
      <CommonTable
        title="Users"
        component="Activity"
        data={{
          Records: [
            {
              EmpCode: "E1",
              EmployeeName: "Alice",
              SystemStatus: "Idle",
              img: "http://example.com/a.png",
              operation_type: "UPDATE",
              old_data: { a: 1 },
              new_data: { a: 2 },
              application_name: "AppX",
              application_count: 1,
              loginDate: "2024-01-01T12:00:00Z",
              duration: 5,
              createdAt: "2024-01-01",
              flag: true,
            },
          ],
          CurrentPage: 1,
          TotalRecords: 1,
          PageSize: 50,
        }}
        columns={[
          { field: "EmpCode", headerName: "EmpCode" },
          { field: "SystemStatus", headerName: "SystemStatus" },
          { field: "img", headerName: "Image" },
          { field: "operation_type", headerName: "Operation" },
          { field: "loginDate", headerName: "Login" },
          { field: "duration", headerName: "Duration", type: Number },
          { field: "createdAt", headerName: "Created", type: Date },
          { field: "flag", headerName: "Flag", type: Boolean },
        ]}
        filters={baseFilters}
        onChange={onChange}
      />
    );

    // Profile link is rendered when permission allows it.
    const profileLink = screen.getByRole("link", { name: "Alice" });
    expect(profileLink).toHaveAttribute("href", "/user-profile/E1");

    // Status class rendering.
    expect(screen.getByText("Idle")).toHaveClass("box", "idle");

    // Screenshot modal.
    fireEvent.click(screen.getByAltText("Image"));
    expect(screen.getByTestId("modal")).toBeInTheDocument();
    expect(screen.getByAltText("Selected")).toHaveAttribute(
      "src",
      "http://example.com/a.png"
    );
    fireEvent.click(screen.getByText("Close"));
    expect(screen.queryByTestId("modal")).not.toBeInTheDocument();

    // Audit-log popup via operation_type.
    fireEvent.click(screen.getByRole("button", { name: "UPDATE" }));
    expect(screen.getByTestId("audit-popup")).toBeInTheDocument();
    fireEvent.click(within(screen.getByTestId("audit-popup")).getByText("Close Popup"));
    expect(screen.queryByTestId("audit-popup")).not.toBeInTheDocument();

    // loginDate string formatting.
    expect(screen.getByText("2024-01-01")).toBeInTheDocument();

    // type handlers.
    expect(screen.getByText("time:5")).toBeInTheDocument();
    expect(screen.getByText("utc:2024-01-01")).toBeInTheDocument();
    expect(screen.getByText("true")).toBeInTheDocument();
  });

  test("Dashboard mode hides pagination and uses dashboard S.No logic", () => {
    const onChange = jest.fn();

    render(
      <CommonTable
        title="Dashboard"
        component="Test"
        data={[{ name: "Alice" }]}
        columns={[{ field: "name", headerName: "Name" }]}
        filters={baseFilters}
        onChange={onChange}
      />
    );

    expect(screen.getByPlaceholderText("Page No")).not.toBeVisible();
    expect(screen.getByText("1")).toBeInTheDocument();
  });
});
