import { describe, it, expect, beforeEach, vi } from 'vitest'
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { MemoryRouter } from 'react-router-dom'

import { BillingPage } from '../BillingPage'
import { useBillingStore } from '@/store/billingStore'
import { BillingPortalError } from '@/types/billing'
import type { SubscriptionState, PlanBillingState } from '@/types/billing'

vi.mock('@/api/billing', () => ({
  billingApi: {
    getPortalSession: vi.fn(),
  },
}))

vi.mock('@/lib/toast', () => ({
  toast: {
    error: vi.fn(),
    success: vi.fn(),
    info: vi.fn(),
    warning: vi.fn(),
  },
}))

import { billingApi } from '@/api/billing'
import { toast } from '@/lib/toast'

const getPortalSession = billingApi.getPortalSession as unknown as ReturnType<typeof vi.fn>
const toastError = toast.error as unknown as ReturnType<typeof vi.fn>

function setBilling(opts: {
  subscription: SubscriptionState | null
  planBilling?: PlanBillingState | null
}) {
  useBillingStore.setState({
    subscription: opts.subscription,
    planBilling:
      opts.planBilling ??
      ({
        display_name: 'Pro',
        description: 'Pro plan',
        monthly_price_cents: 4900,
        annual_price_cents: 49000,
      } as PlanBillingState),
    planLimits: {},
    enabledFeatures: {},
    isLoading: false,
    error: null,
  })
}

function renderPage() {
  return render(
    <MemoryRouter>
      <BillingPage />
    </MemoryRouter>,
  )
}

describe('BillingPage', () => {
  beforeEach(() => {
    getPortalSession.mockReset()
    toastError.mockReset()
    useBillingStore.setState({
      subscription: null,
      planBilling: null,
      planLimits: {},
      enabledFeatures: {},
      isLoading: false,
      error: null,
    })
  })

  it('renders subscription summary from useBillingStore', () => {
    setBilling({
      subscription: {
        status: 'active',
        plan: 'pro',
        current_period_start: '2026-04-01T00:00:00Z',
        current_period_end: '2026-05-01T00:00:00Z',
        cancel_at_period_end: false,
        seat_limit: 5,
        has_pro_entitlement: true,
        is_paid: true,
      },
    })

    renderPage()

    expect(screen.getByRole('heading', { name: 'Billing' })).toBeInTheDocument()
    expect(screen.getByText('Pro')).toBeInTheDocument()
    expect(screen.getByText('Active')).toBeInTheDocument()
    // Seats shown
    expect(screen.getByText('5')).toBeInTheDocument()
  })

  it('shows trial-ends message + Pick a plan CTA when trialing', () => {
    setBilling({
      subscription: {
        status: 'trialing',
        plan: 'pro',
        current_period_start: '2026-04-22T00:00:00Z',
        current_period_end: '2026-05-06T00:00:00Z',
        cancel_at_period_end: false,
        seat_limit: 5,
        has_pro_entitlement: true,
        is_paid: false,
      },
    })

    renderPage()

    expect(screen.getByTestId('trial-message').textContent).toMatch(/Trial ends/)
    const pickPlan = screen.getByTestId('select-plan-link')
    expect(pickPlan.getAttribute('href')).toBe('/account/billing/select-plan')
  })

  it('shows past-due banner with update payment CTA when status=past_due', () => {
    setBilling({
      subscription: {
        status: 'past_due',
        plan: 'pro',
        current_period_start: '2026-04-01T00:00:00Z',
        current_period_end: '2026-05-01T00:00:00Z',
        cancel_at_period_end: false,
        seat_limit: 5,
        has_pro_entitlement: false,
        is_paid: true,
      },
    })

    renderPage()

    expect(screen.getByTestId('past-due-banner')).toBeInTheDocument()
    expect(screen.getByTestId('past-due-update-payment')).toBeInTheDocument()
  })

  it('renders complimentary message and hides CTAs when complimentary', () => {
    setBilling({
      subscription: {
        status: 'complimentary',
        plan: 'pro',
        current_period_start: '2026-04-01T00:00:00Z',
        current_period_end: null,
        cancel_at_period_end: false,
        seat_limit: null,
        has_pro_entitlement: true,
        is_paid: true,
      },
    })

    renderPage()

    expect(screen.getByTestId('complimentary-message')).toBeInTheDocument()
    expect(screen.queryByTestId('manage-billing-button')).not.toBeInTheDocument()
    expect(screen.queryByTestId('select-plan-link')).not.toBeInTheDocument()
    expect(screen.queryByTestId('change-plan-link')).not.toBeInTheDocument()
  })

  it('renders canceled message + Pick a plan CTA when canceled', () => {
    setBilling({
      subscription: {
        status: 'canceled',
        plan: 'pro',
        current_period_start: '2026-03-01T00:00:00Z',
        current_period_end: '2026-04-01T00:00:00Z',
        cancel_at_period_end: false,
        seat_limit: 5,
        has_pro_entitlement: false,
        is_paid: false,
      },
    })

    renderPage()

    expect(screen.getByTestId('canceled-message')).toBeInTheDocument()
    expect(screen.getByTestId('select-plan-link')).toBeInTheDocument()
  })

  it('shows toast when portal session fails with no_stripe_customer', async () => {
    setBilling({
      subscription: {
        status: 'active',
        plan: 'pro',
        current_period_start: '2026-04-01T00:00:00Z',
        current_period_end: '2026-05-01T00:00:00Z',
        cancel_at_period_end: false,
        seat_limit: 5,
        has_pro_entitlement: true,
        is_paid: true,
      },
    })
    getPortalSession.mockRejectedValueOnce(
      new BillingPortalError('no_stripe_customer'),
    )

    renderPage()
    fireEvent.click(screen.getByTestId('manage-billing-button'))

    await waitFor(() => {
      expect(toastError).toHaveBeenCalledWith(
        'Complete checkout first to access billing portal.',
      )
    })
  })
})
