import { renderHook, waitFor } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import type { Cart, CartLine } from '@platform-modules/commerce-cart'
import { CartProvider } from './CartProvider.js'
import { useCart } from './useCart.js'

const ln = (over: Partial<CartLine> = {}): CartLine => ({
  lineId: 'l1', variantId: 'v1', qty: 1,
  price: { amount: 100n, currency: 'USD', priceMode: 'exclusive' }, vendorId: null, ...over,
})
const aCart = (over: Partial<Cart> = {}): Cart => ({ id: 'c1', currency: 'USD', lines: [], subtotal: 0n, ...over })
const wrapper = (cart: Cart) => ({ children }: { children: React.ReactNode }) =>
  <CartProvider client={{ getCart: vi.fn(async () => cart), apply: vi.fn(async () => cart), merge: vi.fn(async () => cart) }} initialCart={cart}>{children}</CartProvider>

describe('useCart', () => {
  it('itemCount = Σ qty', () => {
    const cart = aCart({ lines: [ln({ qty: 2 }), ln({ lineId: 'l2', qty: 3 })], subtotal: 500n })
    const { result } = renderHook(() => useCart(), { wrapper: wrapper(cart) })
    expect(result.current.itemCount).toBe(5)
  })

  it('subtotal passes through cart.subtotal (bigint, never recomputed)', () => {
    const cart = aCart({ lines: [ln()], subtotal: 12345n })
    const { result } = renderHook(() => useCart(), { wrapper: wrapper(cart) })
    expect(result.current.subtotal).toBe(12345n)
  })

  it('byVendor groups a 2-vendor cart; all-null cart → one null-vendor group', () => {
    const two = aCart({ lines: [ln({ vendorId: 'a' }), ln({ lineId: 'l2', vendorId: 'b' })], subtotal: 200n })
    const r2 = renderHook(() => useCart(), { wrapper: wrapper(two) }).result
    expect(r2.current.byVendor?.length).toBe(2)
    const one = aCart({ lines: [ln(), ln({ lineId: 'l2' })], subtotal: 200n })
    const r1 = renderHook(() => useCart(), { wrapper: wrapper(one) }).result
    expect(r1.current.byVendor?.length).toBe(1)
    expect(r1.current.byVendor?.[0]!.vendorId).toBeNull()
  })

  it('null cart → itemCount 0, subtotal null, byVendor null', async () => {
    // not seeded + getCart never resolves → cart stays null while loading
    const pending = new Promise<Cart>(() => {})
    const { result } = renderHook(() => useCart(), {
      wrapper: ({ children }) => <CartProvider client={{ getCart: () => pending, apply: vi.fn(), merge: vi.fn() } as never}>{children}</CartProvider>,
    })
    await waitFor(() => expect(result.current.loading).toBe(true))
    expect(result.current.itemCount).toBe(0)
    expect(result.current.subtotal).toBeNull()
    expect(result.current.byVendor).toBeNull()
  })
})