import { describe, it, expect, vi, afterEach } from 'vitest'
import { renderHook, act, waitFor } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import type { ReactNode } from 'react'

// ─── Mocks ───────────────────────────────────────────────────────────────────

const { createCustomerPortalSessionMock } = vi.hoisted(() => ({
  createCustomerPortalSessionMock: vi.fn(),
}))

vi.mock('../api', () => ({
  createCustomerPortalSession: createCustomerPortalSessionMock,
}))

import { useCustomerPortal } from '../hooks/useCustomerPortal'

afterEach(() => {
  createCustomerPortalSessionMock.mockReset()
})

function wrapper({ children }: { children: ReactNode }) {
  const queryClient = new QueryClient({
    defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
  })
  return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
}

// ─── Tests ───────────────────────────────────────────────────────────────────

describe('useCustomerPortal', () => {
  it("openPortal() succès → window.location.href set sur l'URL portal", async () => {
    const originalLocation = window.location
    const hrefSetter = vi.fn()
    Object.defineProperty(window, 'location', {
      configurable: true,
      writable: true,
      value: {
        ...originalLocation,
        get href() {
          return originalLocation.href
        },
        set href(v: string) {
          hrefSetter(v)
        },
      },
    })

    createCustomerPortalSessionMock.mockResolvedValue({
      url: 'https://billing.stripe.com/p/session/abc',
    })

    const { result } = renderHook(() => useCustomerPortal(), { wrapper })
    act(() => {
      result.current.openPortal()
    })

    await waitFor(() => {
      expect(hrefSetter).toHaveBeenCalledWith('https://billing.stripe.com/p/session/abc')
    })

    Object.defineProperty(window, 'location', {
      configurable: true,
      writable: true,
      value: originalLocation,
    })
  })

  it('erreur backend → message backend propagé dans `error`', async () => {
    createCustomerPortalSessionMock.mockRejectedValue(
      new Error('Aucun abonnement actif trouvé. Souscrivez d’abord à un plan.'),
    )
    const { result } = renderHook(() => useCustomerPortal(), { wrapper })

    act(() => {
      result.current.openPortal()
    })

    await waitFor(() => {
      expect(result.current.error).toMatch(/Aucun abonnement actif trouvé/)
    })
  })

  it('isLoading vrai pendant la mutation pending', async () => {
    createCustomerPortalSessionMock.mockReturnValue(new Promise(() => {}))
    const { result } = renderHook(() => useCustomerPortal(), { wrapper })

    expect(result.current.isLoading).toBe(false)
    act(() => {
      result.current.openPortal()
    })

    await waitFor(() => {
      expect(result.current.isLoading).toBe(true)
    })
  })
})
