import { render, screen, waitFor, cleanup } from "@testing-library/react";
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import AuditPage from "./page";

// Mock next/navigation
const mockPush = vi.fn();
vi.mock("next/navigation", () => ({
  useRouter: () => ({ push: mockPush }),
}));

// Default mock values for admin user
let mockUser: { id: number; email: string; roles: string[]; permissions: string[] } | null = {
  id: 1,
  email: "admin@example.com",
  roles: ["admin"],
  permissions: ["view_audit"],
};
let mockIsLoading = false;
const mockLogout = vi.fn();
const mockHasPermission = vi.fn((permission: string) =>
  mockUser?.permissions.includes(permission) ?? false
);

vi.mock("../auth-context", () => ({
  useAuth: () => ({
    user: mockUser,
    isLoading: mockIsLoading,
    logout: mockLogout,
    hasPermission: mockHasPermission,
  }),
  Permission: {
    VIEW_COUNTER: "view_counter",
    INCREMENT_COUNTER: "increment_counter",
    USE_SUM: "use_sum",
    VIEW_AUDIT: "view_audit",
  },
}));

// Mock fetch
const mockFetch = vi.fn();
global.fetch = mockFetch;

beforeEach(() => {
  vi.clearAllMocks();
  mockUser = {
    id: 1,
    email: "admin@example.com",
    roles: ["admin"],
    permissions: ["view_audit"],
  };
  mockIsLoading = false;
  mockHasPermission.mockImplementation((permission: string) =>
    mockUser?.permissions.includes(permission) ?? false
  );
  // Default: successful empty response
  mockFetch.mockResolvedValue({
    ok: true,
    json: () => Promise.resolve({ records: [], total: 0, page: 1, per_page: 10, total_pages: 1 }),
  });
});

afterEach(() => {
  cleanup();
  vi.restoreAllMocks();
});

describe("AuditPage", () => {
  it("shows loading state", () => {
    mockIsLoading = true;
    render(<AuditPage />);
    expect(screen.getByText("Loading...")).toBeTruthy();
  });

  it("redirects to login when not authenticated", async () => {
    mockUser = null;
    render(<AuditPage />);
    await waitFor(() => {
      expect(mockPush).toHaveBeenCalledWith("/login");
    });
  });

  it("redirects to home when user lacks audit permission", async () => {
    mockUser = {
      id: 1,
      email: "user@example.com",
      roles: ["regular"],
      permissions: ["view_counter"],
    };
    mockHasPermission.mockReturnValue(false);
    render(<AuditPage />);
    await waitFor(() => {
      expect(mockPush).toHaveBeenCalledWith("/");
    });
  });

  it("displays error message when API fetch fails", async () => {
    mockFetch.mockRejectedValue(new Error("Network error"));
    render(<AuditPage />);

    await waitFor(() => {
      // Both tables should show errors since both calls fail
      const errors = screen.getAllByText("Network error");
      expect(errors.length).toBeGreaterThan(0);
    });
  });

  it("displays error when API returns non-ok response", async () => {
    mockFetch.mockResolvedValue({
      ok: false,
      status: 500,
      json: () => Promise.resolve({ detail: "Internal server error" }),
    });

    render(<AuditPage />);

    await waitFor(() => {
      expect(screen.getByText("Failed to load counter records")).toBeTruthy();
    });
  });

  it("displays records when fetch succeeds", async () => {
    const counterResponse = {
      records: [
        {
          id: 1,
          user_email: "recorduser@example.com",
          value_before: 0,
          value_after: 1,
          created_at: "2024-01-01T00:00:00Z",
        },
      ],
      total: 1,
      page: 1,
      per_page: 10,
      total_pages: 1,
    };
    
    const sumResponse = {
      records: [],
      total: 0,
      page: 1,
      per_page: 10,
      total_pages: 1,
    };

    mockFetch
      .mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve(counterResponse),
      })
      .mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve(sumResponse),
      });

    render(<AuditPage />);

    await waitFor(() => {
      expect(screen.getByText("recorduser@example.com")).toBeTruthy();
    });
  });

  it("shows table headers", async () => {
    render(<AuditPage />);

    await waitFor(() => {
      // Check for counter table headers
      expect(screen.getByText("Counter Activity")).toBeTruthy();
      expect(screen.getByText("Sum Activity")).toBeTruthy();
    });
  });
});
