import { renderHook, waitFor } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import type { ReactNode } from 'react'
import { OrdersProvider } from './OrdersProvider.js'
import { useOrder } from './useOrder.js'
import type { OrdersClient } from './client.js'
import type { Order } from '@platform-modules/commerce-orders'

function fixture(id = 'o1'): Order {
  return {
    id, buyerRef: { userId: 'u1' }, status: 'paid', currency: 'USD', priceMode: 'exclusive',
    subtotal: 1000n, tax: 90n, discount: 0n, total: 1090n,
    lines: [], splits: [], fulfillmentState: { steps: {} },
  }
}

function wrap(client: OrdersClient) {
  return ({ children }: { children: ReactNode }) => <OrdersProvider client={client}>{children}</OrdersProvider>
}

describe('useOrder', () => {
  it('seeded → loading:false, no mount fetch', () => {
    const getOrderById = vi.fn()
    const client: OrdersClient = { getOrderById, listOrders: vi.fn() }
    const { result } = renderHook(() => useOrder('o1', { initialData: fixture() }), { wrapper: wrap(client) })
    expect(result.current.loading).toBe(false)
    expect(result.current.order?.total).toBe(1090n)
    expect(getOrderById).not.toHaveBeenCalled()
  })

  it('unseeded → fetches on mount', async () => {
    const getOrderById = vi.fn(async () => fixture())
    const client: OrdersClient = { getOrderById, listOrders: vi.fn() }
    const { result } = renderHook(() => useOrder('o1'), { wrapper: wrap(client) })
    await waitFor(() => expect(result.current.loading).toBe(false))
    expect(result.current.order?.id).toBe('o1')
    expect(getOrderById).toHaveBeenCalledWith('o1')
  })

  it('null result (not found / not entitled) is NOT an error', async () => {
    const client: OrdersClient = { getOrderById: async () => null, listOrders: vi.fn() }
    const { result } = renderHook(() => useOrder('o1'), { wrapper: wrap(client) })
    await waitFor(() => expect(result.current.loading).toBe(false))
    expect(result.current.order).toBeNull()
    expect(result.current.error).toBeNull()
  })

  it('client error surfaces on error (not thrown)', async () => {
    const client: OrdersClient = { getOrderById: async () => { throw new Error('boom') }, listOrders: vi.fn() }
    const { result } = renderHook(() => useOrder('o1'), { wrapper: wrap(client) })
    await waitFor(() => expect(result.current.error).toBeTruthy())
    expect(result.current.error?.message).toBe('boom')
  })

  it('reload refetches', async () => {
    const getOrderById = vi.fn(async () => fixture())
    const client: OrdersClient = { getOrderById, listOrders: vi.fn() }
    const { result } = renderHook(() => useOrder('o1'), { wrapper: wrap(client) })
    await waitFor(() => expect(result.current.loading).toBe(false))
    result.current.reload()
    await waitFor(() => expect(getOrderById).toHaveBeenCalledTimes(2))
  })
})
