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

// ── Mocks ────────────────────────────────────────────────────────────────────

const mockPostApi = jest.fn();

jest.unstable_mockModule("react-toastify", () => ({ 
  toast: { error: jest.fn() } 
}));

jest.unstable_mockModule("../context/UserContext.js", () => ({
  useUser: () => ({
    permissions: [
      {
        SubMenuItems: [
          { SubFeatureName: "Screenshots", Permission_Id: "1" },
        ],
      },
    ],
  }),
}));

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

// Stub heavy child components so tests stay fast & focused
jest.unstable_mockModule("../components/Profile.js", () => ({
  default: ({ EmployeeName, employeeId }) => (
    <div data-testid="profile">{EmployeeName || employeeId}</div>
  ),
}));
jest.unstable_mockModule("../pages/ActivityReports/EmployeeWorkingTime.js", () => ({
  default: () => <div data-testid="employee-working-time" />,
}));
jest.unstable_mockModule("../pages/ActivityReports/CallDetails.js", () => ({
  default: () => <div data-testid="call-details" />,
}));
jest.unstable_mockModule("../pages/ActivityReports/RunningApplicationDetails.js", () => ({
  default: () => <div data-testid="running-app-details" />,
}));
jest.unstable_mockModule("../pages/ActivityReports/SystemLoginDetails.js", () => ({
  default: () => <div data-testid="system-login-details" />,
}));
jest.unstable_mockModule("../pages/ActivityReports/Screenshots.js", () => ({
  default: () => <div data-testid="screenshots" />,
}));
jest.unstable_mockModule("../pages/ActivityReports/SystemActivityScreen.js", () => ({
  default: () => <div data-testid="system-activity" />,
}));
jest.unstable_mockModule("../pages/ActivityTable.js", () => ({
  default: () => <div data-testid="activity-table" />,
}));
jest.unstable_mockModule("../pages/BrowsingHistory.js", () => ({
  default: () => <div data-testid="browsing-history" />,
}));
jest.unstable_mockModule("../components/UserLocation.js", () => ({
  default: () => <div data-testid="user-location" />,
}));
jest.unstable_mockModule("../components/DateRangePicker.js", () => ({
  default: ({ onApply, onClose }) => (
    <div data-testid="date-range-picker">
      <button onClick={() => { onApply && onApply(); onClose && onClose(); }}>Apply Range</button>
      <button onClick={onClose}>Close</button>
    </div>
  ),
}));
jest.unstable_mockModule("../components/SingleDatePicker.js", () => ({
  default: ({ onApply, onClose }) => (
    <div data-testid="single-date-picker">
      <button onClick={() => { onApply && onApply(); onClose && onClose(); }}>Apply Single</button>
      <button onClick={onClose}>Close</button>
    </div>
  ),
}));
jest.unstable_mockModule("../components/Loader.js", () => ({
  default: () => <div data-testid="loader" />,
}));

// SVG assets
jest.unstable_mockModule("../assets/svg/profile-work-log.svg", () => ({
  default: (props) => <svg data-testid="work-log-svg" {...props} />,
}));
jest.unstable_mockModule("../assets/svg/profile-calls.svg", () => ({
  default: (props) => <svg data-testid="calls-svg" {...props} />,
}));
jest.unstable_mockModule("../assets/svg/profile-apps.svg", () => ({
  default: (props) => <svg data-testid="apps-svg" {...props} />,
}));
jest.unstable_mockModule("../assets/svg/profile-browser.svg", () => ({
  default: (props) => <svg data-testid="browser-svg" {...props} />,
}));
jest.unstable_mockModule("../assets/svg/profile-login-attempts.svg", () => ({
  default: (props) => <svg data-testid="login-svg" {...props} />,
}));
jest.unstable_mockModule("../assets/svg/profile-location.svg", () => ({
  default: (props) => <svg data-testid="location-svg" {...props} />,
}));
jest.unstable_mockModule("../assets/svg/back.svg", () => ({
  default: (props) => <svg data-testid="back-svg" {...props} />,
}));

jest.unstable_mockModule("../constants/apiEndPoints.js", () => ({ 
  getUserSummaryDetails: "/api/user-summary" 
}));
jest.unstable_mockModule("../utils/secondToTime.js", () => ({
  default: (seconds) => {
    const hours = Math.floor(seconds / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);
    const secs = seconds % 60;
    return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
  },
}));
jest.unstable_mockModule("../constants/userConstants.js", () => ({
  permissionTypes: [{ key: 1 }, { key: 2 }, { key: 3 }],
}));

// Import component and toast after all mocks
const { default: UserProfile } = await import("../pages/UserProfile/UserProfile.js");
const { toast } = await import("react-toastify");

// ── Helpers ───────────────────────────────────────────────────────────────────

const SUMMARY_RECORD = {
  EmployeeName: "Jane Doe",
  Location: "New York",
  total_active_time: 3600,
  total_call_count: 5,
  total_call_duration: 1800,
  total_application_count: 10,
  total_application_count_time: 900,
  total_browsing_count: 3,
  total_browsing_time: 600,
  total_login_count: 2,
  total_location_count: 1,
};

const successResponse = {
  IsSuccess: true,
  Data: { Records: [SUMMARY_RECORD] },
};

const renderComponent = (empCode = "EMP001", props = {}) =>
  render(
    <MemoryRouter initialEntries={[`/users/${empCode}`]}>
      <Routes>
        <Route path="/users/:empCode" element={<UserProfile title="User Profile" {...props} />} />
      </Routes>
    </MemoryRouter>
  );

// ── Tests ─────────────────────────────────────────────────────────────────────

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

  // ── Rendering ──────────────────────────────────────────────────────────────

  describe("Initial rendering", () => {
    it("renders the page title passed via props", async () => {
      mockPostApi.mockResolvedValueOnce(successResponse);
      await act(async () => renderComponent());
      expect(screen.getByText("User Profile")).toBeInTheDocument();
    }, 15000);

    it(
      "renders the Back to User List link",
      async () => {
        mockPostApi.mockResolvedValueOnce(successResponse);
        await act(async () => renderComponent());
        await waitFor(() => {
          expect(screen.getByText("Back to User List")).toBeInTheDocument();
        });
      },
      10000
    );

    it("renders the Profile component", async () => {
      mockPostApi.mockResolvedValueOnce(successResponse);
      await act(async () => renderComponent());
      expect(screen.getByTestId("profile")).toBeInTheDocument();
    });

    it.skip("renders all six summary cards", async () => {
      mockPostApi.mockResolvedValueOnce(successResponse);
      await act(async () => renderComponent());
      await waitFor(() => {
        expect(screen.getByTestId("work-log-svg")).toBeInTheDocument();
        expect(screen.getByTestId("calls-svg")).toBeInTheDocument();
        expect(screen.getByTestId("apps-svg")).toBeInTheDocument();
        expect(screen.getByTestID("browser-svg")).toBeInTheDocument();
        expect(screen.getByTestId("login-svg")).toBeInTheDocument();
        expect(screen.getByTestId("location-svg")).toBeInTheDocument();
      });
    });

    it("shows the Loader while fetching", async () => {
      let resolve;
      mockPostApi.mockReturnValueOnce(new Promise((r) => (resolve = r)));
      act(() => renderComponent());
      expect(screen.getByTestId("loader")).toBeInTheDocument();
      await act(async () => resolve(successResponse));
    });

    it("hides the Loader after data loads", async () => {
      mockPostApi.mockResolvedValueOnce(successResponse);
      await act(async () => renderComponent());
      expect(screen.queryByTestId("loader")).not.toBeInTheDocument();
    });
  });

  // ── API call ───────────────────────────────────────────────────────────────

  describe("API interaction", () => {
    it("calls postApi on mount", async () => {
      mockPostApi.mockResolvedValueOnce(successResponse);
      await act(async () => renderComponent());
      expect(mockPostApi).toHaveBeenCalledTimes(1);
    });

    it("passes the correct empCode from the URL to the API filter", async () => {
      mockPostApi.mockResolvedValueOnce(successResponse);
      await act(async () => renderComponent("EMP042"));
      const [, payload] = mockPostApi.mock.calls[0];
      expect(payload.Filter.EmpCode).toBe("EMP042");
    });

    it("displays employee name after successful API response", async () => {
      mockPostApi.mockResolvedValueOnce(successResponse);
      await act(async () => renderComponent());
      expect(screen.getByTestId("profile")).toHaveTextContent("Jane Doe");
    });

    it("shows error toast when API throws", async () => {
      mockPostApi.mockRejectedValueOnce(new Error("Network error"));
      await act(async () => renderComponent());
      expect(toast.error).toHaveBeenCalledWith("Something went wrong", "Network error");
    });

    it("does not crash when API returns empty records", async () => {
      mockPostApi.mockResolvedValueOnce({ IsSuccess: true, Data: { Records: [] } });
      await act(async () => renderComponent());
      expect(screen.getByText("User Profile")).toBeInTheDocument();
    });

    it("does not crash when API returns IsSuccess: false", async () => {
      mockPostApi.mockResolvedValueOnce({ IsSuccess: false });
      await act(async () => renderComponent());
      expect(screen.getByText("User Profile")).toBeInTheDocument();
    });
  });

  // ── Summary card values ────────────────────────────────────────────────────

  describe("Summary card data display", () => {
    beforeEach(() => mockPostApi.mockResolvedValue(successResponse));

    it("shows call count from API data", async () => {
      await act(async () => renderComponent());
      expect(screen.getByText(/5 Calls/i)).toBeInTheDocument();
    });

    it("shows application count from API data", async () => {
      await act(async () => renderComponent());
      expect(screen.getByText(/10 Apps/i)).toBeInTheDocument();
    });

    it("shows browsing count from API data", async () => {
      await act(async () => renderComponent());
      expect(screen.getByText(/3 Browsers used/i)).toBeInTheDocument();
    });

    it("shows login attempts count from API data", async () => {
      await act(async () => renderComponent());
      expect(screen.getByText(/2 Login Attempts/i)).toBeInTheDocument();
    });

    it("shows location count from API data", async () => {
      await act(async () => renderComponent());
      expect(screen.getByText(/1 Locations/i)).toBeInTheDocument();
    });

    it("shows 'No Calls' when total_call_count is 0", async () => {
      mockPostApi.mockResolvedValueOnce({
        IsSuccess: true,
        Data: { Records: [{ ...SUMMARY_RECORD, total_call_count: 0 }] },
      });
      await act(async () => renderComponent());
      expect(screen.getByText(/No Calls/i)).toBeInTheDocument();
    });
  });

  // ── Tabs ───────────────────────────────────────────────────────────────────

  describe("Tab rendering and navigation", () => {
    beforeEach(() => mockPostApi.mockResolvedValue(successResponse));

    it("renders Work Log tab by default (index 0)", async () => {
      await act(async () => renderComponent());
      expect(screen.getByTestId("employee-working-time")).toBeInTheDocument();
    }, 15000);

    it("switches to Call Activity Log tab", async () => {
      await act(async () => renderComponent());
      fireEvent.click(screen.getByRole("tab", { name: /call activity log/i }));
      await waitFor(() => expect(screen.getByTestId("call-details")).toBeInTheDocument());
    }, 15000);

    it("switches to Browsing History tab", async () => {
      await act(async () => renderComponent());
      fireEvent.click(screen.getByRole("tab", { name: /browsing history/i }));
      await waitFor(() => expect(screen.getByTestId("browsing-history")).toBeInTheDocument());
    }, 15000);

    it("switches to Login Details tab", async () => {
      await act(async () => renderComponent());
      fireEvent.click(screen.getByRole("tab", { name: /login details/i }));
      await waitFor(() => expect(screen.getByTestId("system-login-details")).toBeInTheDocument());
    }, 15000);

    it("switches to User Location tab", async () => {
      await act(async () => renderComponent());
      fireEvent.click(screen.getByRole("tab", { name: /user location/i }));
      await waitFor(() => expect(screen.getByTestId("user-location")).toBeInTheDocument());
    }, 15000);

    it("switches to System Activity tab", async () => {
      await act(async () => renderComponent());
      fireEvent.click(screen.getByRole("tab", { name: /system activity/i }));
      await waitFor(() => expect(screen.getByTestId("activity-table")).toBeInTheDocument());
    }, 15000);

    it("renders Screenshots tab when permission allows", async () => {
      await act(async () => renderComponent());
      expect(screen.getByRole("tab", { name: /screenshots/i })).toBeInTheDocument();
    });

    it("navigates to Screenshots tab on click", async () => {
      await act(async () => renderComponent());
      fireEvent.click(screen.getByRole("tab", { name: /screenshots/i }));
      await waitFor(() => expect(screen.getByTestId("screenshots")).toBeInTheDocument());
    });

    it("clicking a summary card NavigateNext icon switches to matching tab", async () => {
      await act(async () => renderComponent());
      // Second card is Call Log (index 1)
      const navButtons = screen.getAllByLabelText("more");
      fireEvent.click(navButtons[1]);
      await waitFor(() => expect(screen.getByTestId("call-details")).toBeInTheDocument());
    });
  });

  // ── Filters ────────────────────────────────────────────────────────────────

  describe("Filter controls", () => {
    beforeEach(() => mockPostApi.mockResolvedValue(successResponse));

    it("renders the ResultsFor dropdown with default 'Today'", async () => {
      await act(async () => renderComponent());
      // MUI Select renders selected value as text
      expect(screen.getByText("Today")).toBeInTheDocument();
    });

    it("renders the date range input placeholder", async () => {
      await act(async () => renderComponent());
      expect(screen.getByPlaceholderText("Select Date Range")).toBeInTheDocument();
    });

    it("opens date range picker when date input is clicked (non-system-activity tab)", async () => {
      await act(async () => renderComponent());
      fireEvent.click(screen.getByPlaceholderText("Select Date Range"));
      expect(screen.getByTestId("date-range-picker")).toBeInTheDocument();
    });

    it.skip("closes date range picker on Apply", async () => {
      await act(async () => renderComponent());
      fireEvent.click(screen.getByPlaceholderText("Select Date Range"));
      fireEvent.click(screen.getByText("Apply Range"));
      await waitFor(() =>
        expect(screen.queryByTestId("date-range-picker")).not.toBeInTheDocument()
      );
    });

    it("closes date range picker on Close", async () => {
      await act(async () => renderComponent());
      fireEvent.click(screen.getByPlaceholderText("Select Date Range"));
      fireEvent.click(screen.getByText("Close"));
      await waitFor(() =>
        expect(screen.queryByTestId("date-range-picker")).not.toBeInTheDocument()
      );
    });

    it("shows SingleDatePicker on System Activity tab", async () => {
      await act(async () => renderComponent());
      fireEvent.click(screen.getByRole("tab", { name: /system activity/i }));
      fireEvent.click(screen.getByRole("textbox")); // date input
      expect(screen.getByTestId("single-date-picker")).toBeInTheDocument();
    });

    it("calls getSummaryData (postApi) when Apply button is clicked", async () => {
      await act(async () => renderComponent());
      mockPostApi.mockResolvedValueOnce(successResponse);
      fireEvent.click(screen.getByRole("button", { name: /apply/i }));
      await waitFor(() => expect(mockPostApi).toHaveBeenCalledTimes(2));
    });

    it("resets filters and calls getSummaryData when clear (FilterAltOff) button is clicked", async () => {
      await act(async () => renderComponent());
      mockPostApi.mockResolvedValueOnce(successResponse);
      // The FilterAltOff button is the second contained button in filter area
      const buttons = screen.getAllByRole("button", { name: "" });
      fireEvent.click(buttons[buttons.length - 1]); // last icon button in filter row
      await waitFor(() => expect(mockPostApi).toHaveBeenCalledTimes(2));
    });
  });

  // ── Accessibility ─────────────────────────────────────────────────────────

  describe("Accessibility", () => {
    beforeEach(() => mockPostApi.mockResolvedValue(successResponse));

    it("tabs have correct aria-controls attributes", async () => {
      await act(async () => renderComponent());
      const firstTab = screen.getByRole("tab", { name: /work log/i });
      expect(firstTab).toHaveAttribute("aria-controls", "simple-tabpanel-0");
    });

    it("inactive tab panels are hidden", async () => {
      await act(async () => renderComponent());
      const panels = screen.getAllByRole("tabpanel", { hidden: true });
      const hiddenPanels = panels.filter(
        (p) => p.getAttribute("hidden") !== null
      );
      expect(hiddenPanels.length).toBeGreaterThan(0);
    });
  });
});