import { renderHook, waitFor } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import type { ReactNode } from 'react'
import type { Vendor } from '@platform-modules/commerce-marketplace'
import { MarketplaceProvider } from './MarketplaceProvider.js'
import { useVendorProfile } from './useVendorProfile.js'
import type { MarketplaceClient } from './client.js'

const wireVendor = {
  id: 'v1',
  ownerUserId: 'u1',
  name: 'Test',
  status: 'approved' as const,
  commissionBps: 1000,
  createdAt: new Date().toISOString(),
  updatedAt: new Date().toISOString(),
}

function fixture(): Vendor {
  return {
    id: 'v1',
    ownerUserId: 'u1',
    name: 'Test',
    status: 'approved',
    commissionBps: 1000,
    createdAt: new Date(wireVendor.createdAt),
    updatedAt: new Date(wireVendor.updatedAt),
  }
}

function wrap(client: MarketplaceClient) {
  return ({ children }: { children: ReactNode }) => (
    <MarketplaceProvider client={client}>{children}</MarketplaceProvider>
  )
}

function baseClient(overrides: Partial<MarketplaceClient> = {}): MarketplaceClient {
  return {
    getVendorProfile: vi.fn(async () => wireVendor),
    getVendorOrders: vi.fn(),
    applyAsVendor: vi.fn(),
    createVendorProduct: vi.fn(),
    updateVendorProduct: vi.fn(),
    ...overrides,
  }
}

describe('useVendorProfile', () => {
  it('seed with valid vendor → data equals seed, no mount fetch', () => {
    const getVendorProfile = vi.fn()
    const client = baseClient({ getVendorProfile })
    const seeded = fixture()
    const { result } = renderHook(() => useVendorProfile({ initialData: seeded }), { wrapper: wrap(client) })
    expect(result.current.vendor).toEqual(seeded)
    expect(getVendorProfile).not.toHaveBeenCalled()
  })

  it('seed with null → data is null, no mount fetch', () => {
    const getVendorProfile = vi.fn()
    const client = baseClient({ getVendorProfile })
    const { result } = renderHook(() => useVendorProfile({ initialData: null }), { wrapper: wrap(client) })
    expect(result.current.vendor).toBeNull()
    expect(getVendorProfile).not.toHaveBeenCalled()
  })

  it('unseeded → fetches on mount and revives vendor', async () => {
    const getVendorProfile = vi.fn(async () => wireVendor)
    const client = baseClient({ getVendorProfile })
    const { result } = renderHook(() => useVendorProfile(), { wrapper: wrap(client) })
    await waitFor(() => expect(result.current.loading).toBe(false))
    expect(getVendorProfile).toHaveBeenCalledTimes(1)
    expect(result.current.vendor).toEqual(fixture())
  })

  it('null result is not an error', async () => {
    const client = baseClient({ getVendorProfile: vi.fn(async () => null) })
    const { result } = renderHook(() => useVendorProfile(), { wrapper: wrap(client) })
    await waitFor(() => expect(result.current.loading).toBe(false))
    expect(result.current.vendor).toBeNull()
    expect(result.current.error).toBeNull()
  })

  it('client error surfaces on error (not thrown)', async () => {
    const client = baseClient({
      getVendorProfile: vi.fn(async () => {
        throw new Error('boom')
      }),
    })
    const { result } = renderHook(() => useVendorProfile(), { wrapper: wrap(client) })
    await waitFor(() => expect(result.current.error).toBeTruthy())
    expect(result.current.error?.message).toBe('boom')
    expect(result.current.vendor).toBeNull()
  })

  it('reload refetches', async () => {
    const getVendorProfile = vi.fn(async () => wireVendor)
    const client = baseClient({ getVendorProfile })
    const { result } = renderHook(() => useVendorProfile(), { wrapper: wrap(client) })
    await waitFor(() => expect(result.current.loading).toBe(false))
    result.current.reload()
    await waitFor(() => expect(getVendorProfile).toHaveBeenCalledTimes(2))
  })
})
