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

const mockUseQuery = vi.fn();

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

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

const sampleOrder = {
  _id: "order_abc",
  _creationTime: 1700000000000,
  orderNumber: "ORD-ABCDE",
  status: "confirmed",
  paymentStatus: "paid",
  total: 2500,
  currency: "GBP",
  subtotal: 2000,
  tax: 200,
  shipping: 500,
  discount: 200,
  email: "alice@example.com",
  createdAt: 1700000000000,
  updatedAt: 1700000000000,
  shippingMethod: "Standard",
  carrier: "DPD",
  shippoShipmentId: "shp_123",
  shippingAddressSnapshot: {
    fullName: "Alice Smith",
    firstName: "Alice",
    lastName: "Smith",
    addressLine1: "1 Test St",
    city: "London",
    postalCode: "E1 1AA",
    country: "GB",
  },
  billingAddressSnapshot: {
    firstName: "Alice",
    lastName: "Smith",
    addressLine1: "1 Test St",
    city: "London",
    postalCode: "E1 1AA",
    country: "GB",
  },
  items: [
    {
      _id: "item_1",
      variantId: "var_1",
      productName: "Dog Toy",
      variantName: "Red",
      sku: "TOY-RED-001",
      quantity: 2,
      unitPrice: 999,
      totalPrice: 1998,
    },
  ],
};

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

  it("returns loading state when query returns undefined", () => {
    mockUseQuery.mockReturnValue(undefined);

    const { result } = renderHook(() => useOrderDetail("order_abc"));

    expect(result.current.isLoading).toBe(true);
    expect(result.current.order).toBeNull();
    expect(result.current.error).toBeNull();
  });

  it("calls useQuery with the correct function ref and orderId", () => {
    mockUseQuery.mockReturnValue(undefined);

    renderHook(() => useOrderDetail("order_abc"));

    expect(mockUseQuery).toHaveBeenCalledWith("mock-getById-ref", {
      id: "order_abc",
    });
  });

  it("returns order data when query resolves successfully", () => {
    mockUseQuery.mockReturnValue(sampleOrder);

    const { result } = renderHook(() => useOrderDetail("order_abc"));

    expect(result.current.isLoading).toBe(false);
    expect(result.current.error).toBeNull();
    expect(result.current.order).not.toBeNull();
    expect(result.current.order?._id).toBe("order_abc");
    expect(result.current.order?.orderNumber).toBe("ORD-ABCDE");
    expect(result.current.order?.status).toBe("confirmed");
  });

  it("returns null order (not loading) when query returns null", () => {
    mockUseQuery.mockReturnValue(null);

    const { result } = renderHook(() => useOrderDetail("order_abc"));

    expect(result.current.isLoading).toBe(false);
    expect(result.current.order).toBeNull();
    expect(result.current.error).toBeNull();
  });

  it("exposes order items through the order object", () => {
    mockUseQuery.mockReturnValue(sampleOrder);

    const { result } = renderHook(() => useOrderDetail("order_abc"));

    expect(result.current.order?.items).toHaveLength(1);
    expect(result.current.order?.items[0].productName).toBe("Dog Toy");
    expect(result.current.order?.items[0].quantity).toBe(2);
  });

  it("transitions from loading to resolved when query returns data", () => {
    mockUseQuery.mockReturnValueOnce(undefined).mockReturnValueOnce(sampleOrder);

    const { result, rerender } = renderHook(() => useOrderDetail("order_abc"));
    expect(result.current.isLoading).toBe(true);

    rerender();
    expect(result.current.isLoading).toBe(false);
    expect(result.current.order?._id).toBe("order_abc");
  });

  it("error is always null (errors bubble to error boundaries)", () => {
    mockUseQuery.mockReturnValue(sampleOrder);

    const { result } = renderHook(() => useOrderDetail("order_abc"));

    expect(result.current.error).toBeNull();
  });
});
