/**
 * @vitest-environment happy-dom
 */
import { describe, it, expect, vi, beforeEach } from "vitest";
import { renderHook } from "@testing-library/react";
import { useOrders } from "./useOrders";
import { ORDERS_PAGE_SIZE } from "./constants";

const mockLoadMore = vi.fn();
const mockUsePaginatedQuery = vi.fn();

vi.mock("convex/react", () => ({
  usePaginatedQuery: (...args: unknown[]) => mockUsePaginatedQuery(...args),
}));

vi.mock("../../../../../convex/_generated/api", () => ({
  api: {
    orders: { listMine: "mock-listMine-ref" },
  },
}));

const sampleOrder = {
  _id: "order_1",
  _creationTime: 1700000000000,
  orderNumber: "ORD-ABCDE",
  status: "confirmed",
  paymentStatus: "paid",
  total: 2500,
  currency: "GBP",
  createdAt: 1700000000000,
  updatedAt: 1700000000000,
  shippingMethod: "Standard",
  carrier: "DPD",
  shippingAddressSnapshot: {
    fullName: "Alice",
    firstName: "Alice",
    lastName: "Smith",
    addressLine1: "1 Test St",
    city: "London",
    postalCode: "E1 1AA",
    country: "GB",
  },
};

describe("useOrders", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("returns loading state when status is LoadingFirstPage", () => {
    mockUsePaginatedQuery.mockReturnValue({
      results: [],
      status: "LoadingFirstPage",
      loadMore: mockLoadMore,
    });

    const { result } = renderHook(() => useOrders());

    expect(result.current.isLoading).toBe(true);
    expect(result.current.orders).toEqual([]);
    expect(result.current.hasMore).toBe(false);
  });

  it("returns orders and hasMore=true when status is CanLoadMore", () => {
    mockUsePaginatedQuery.mockReturnValue({
      results: [sampleOrder],
      status: "CanLoadMore",
      loadMore: mockLoadMore,
    });

    const { result } = renderHook(() => useOrders());

    expect(result.current.isLoading).toBe(false);
    expect(result.current.orders).toHaveLength(1);
    expect(result.current.orders[0]._id).toBe("order_1");
    expect(result.current.hasMore).toBe(true);
  });

  it("returns hasMore=false when status is Exhausted", () => {
    mockUsePaginatedQuery.mockReturnValue({
      results: [sampleOrder],
      status: "Exhausted",
      loadMore: mockLoadMore,
    });

    const { result } = renderHook(() => useOrders());

    expect(result.current.hasMore).toBe(false);
    expect(result.current.isLoading).toBe(false);
  });

  it("passes through the raw Convex status", () => {
    for (const status of [
      "LoadingFirstPage",
      "LoadingMore",
      "CanLoadMore",
      "Exhausted",
    ] as const) {
      mockUsePaginatedQuery.mockReturnValue({
        results: [],
        status,
        loadMore: mockLoadMore,
      });
      const { result } = renderHook(() => useOrders());
      expect(result.current.status).toBe(status);
    }
  });

  it("calls usePaginatedQuery with the listMine ref and ORDERS_PAGE_SIZE", () => {
    mockUsePaginatedQuery.mockReturnValue({
      results: [],
      status: "Exhausted",
      loadMore: mockLoadMore,
    });

    renderHook(() => useOrders());

    expect(mockUsePaginatedQuery).toHaveBeenCalledWith(
      "mock-listMine-ref",
      { statusFilter: undefined },
      { initialNumItems: ORDERS_PAGE_SIZE },
    );
  });

  it("passes statusFilter to usePaginatedQuery when provided", () => {
    mockUsePaginatedQuery.mockReturnValue({
      results: [],
      status: "Exhausted",
      loadMore: mockLoadMore,
    });

    renderHook(() => useOrders(["confirmed", "processing"]));

    expect(mockUsePaginatedQuery).toHaveBeenCalledWith(
      "mock-listMine-ref",
      { statusFilter: ["confirmed", "processing"] },
      { initialNumItems: ORDERS_PAGE_SIZE },
    );
  });

  it("passes statusFilter as undefined when an empty array is provided", () => {
    mockUsePaginatedQuery.mockReturnValue({
      results: [],
      status: "Exhausted",
      loadMore: mockLoadMore,
    });

    renderHook(() => useOrders([]));

    expect(mockUsePaginatedQuery).toHaveBeenCalledWith(
      "mock-listMine-ref",
      { statusFilter: undefined },
      { initialNumItems: ORDERS_PAGE_SIZE },
    );
  });

  it("loadMore calls usePaginatedQuery's loadMore with ORDERS_PAGE_SIZE", () => {
    mockUsePaginatedQuery.mockReturnValue({
      results: [],
      status: "CanLoadMore",
      loadMore: mockLoadMore,
    });

    const { result } = renderHook(() => useOrders());
    result.current.loadMore();

    expect(mockLoadMore).toHaveBeenCalledWith(ORDERS_PAGE_SIZE);
  });

  it("returns isLoading=false during LoadingMore (data already present)", () => {
    mockUsePaginatedQuery.mockReturnValue({
      results: [sampleOrder],
      status: "LoadingMore",
      loadMore: mockLoadMore,
    });

    const { result } = renderHook(() => useOrders());

    expect(result.current.isLoading).toBe(false);
    expect(result.current.orders).toHaveLength(1);
  });
});
