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

import { SelectPlanPage } from '../SelectPlanPage'
import { useBillingStore } from '@/store/billingStore'

vi.mock('@/api/billing', () => ({
  billingApi: {
    createCheckoutSession: vi.fn(),
  },
}))
vi.mock('@/api/plans', () => ({
  plansApi: {
    getPublic: vi.fn(),
  },
}))
vi.mock('@/lib/toast', () => ({
  toast: {
    error: vi.fn(),
    success: vi.fn(),
  },
}))

import { billingApi } from '@/api/billing'
import { plansApi } from '@/api/plans'

const createCheckoutSession = billingApi.createCheckoutSession as unknown as ReturnType<typeof vi.fn>
const getPublic = plansApi.getPublic as unknown as ReturnType<typeof vi.fn>

const PLAN_FIXTURE = [
  {
    plan: 'starter',
    display_name: 'Starter',
    description: 'For solo techs.',
    monthly_price_cents: 1900,
    annual_price_cents: 19000,
    max_seats: 1,
    sort_order: 1,
    is_public: true,
  },
  {
    plan: 'pro',
    display_name: 'Pro',
    description: 'For growing teams.',
    monthly_price_cents: 4900,
    annual_price_cents: 49000,
    max_seats: 5,
    sort_order: 2,
    is_public: true,
  },
  {
    plan: 'enterprise',
    display_name: 'Enterprise',
    description: 'Custom.',
    monthly_price_cents: null,
    annual_price_cents: null,
    max_seats: null,
    sort_order: 3,
    is_public: true,
  },
]

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

describe('SelectPlanPage', () => {
  // Stub window.location.href setter so we can assert without a real navigation.
  let assignedHref: string | null = null
  const originalLocation = window.location

  beforeEach(() => {
    getPublic.mockReset()
    createCheckoutSession.mockReset()
    assignedHref = null
    Object.defineProperty(window, 'location', {
      configurable: true,
      value: {
        ...originalLocation,
        get href() {
          return assignedHref ?? originalLocation.href
        },
        set href(v: string) {
          assignedHref = v
        },
      },
    })
    useBillingStore.setState({
      subscription: null,
      planBilling: null,
      planLimits: {},
      enabledFeatures: {},
      isLoading: false,
      error: null,
    })
  })

  it('renders plan cards from plansApi', async () => {
    getPublic.mockResolvedValueOnce(PLAN_FIXTURE)
    renderPage()

    await waitFor(() => {
      expect(screen.getByTestId('plan-card-starter')).toBeInTheDocument()
    })
    expect(screen.getByTestId('plan-card-pro')).toBeInTheDocument()
    expect(screen.getByTestId('plan-card-enterprise')).toBeInTheDocument()
  })

  it('Continue to checkout calls createCheckoutSession and redirects', async () => {
    getPublic.mockResolvedValueOnce(PLAN_FIXTURE)
    createCheckoutSession.mockResolvedValueOnce({ url: 'https://checkout.stripe.com/abc' })

    renderPage()
    await waitFor(() => {
      expect(screen.getByTestId('plan-card-pro')).toBeInTheDocument()
    })

    // Bump seats and switch to annual.
    fireEvent.change(screen.getByTestId('seats-input'), { target: { value: '3' } })
    fireEvent.click(screen.getByTestId('interval-annual'))

    fireEvent.click(screen.getByTestId('plan-cta-pro'))

    await waitFor(() => {
      expect(createCheckoutSession).toHaveBeenCalledWith({
        plan: 'pro',
        seats: 3,
        billing_interval: 'annual',
      })
    })
    await waitFor(() => {
      expect(assignedHref).toBe('https://checkout.stripe.com/abc')
    })
  })

  it('Talk to sales links to /contact-sales for enterprise', async () => {
    getPublic.mockResolvedValueOnce(PLAN_FIXTURE)
    renderPage()
    await waitFor(() => {
      expect(screen.getByTestId('plan-cta-enterprise')).toBeInTheDocument()
    })
    const cta = screen.getByTestId('plan-cta-enterprise') as HTMLAnchorElement
    expect(cta.getAttribute('href')).toBe('/contact-sales')
  })

  it('marks the active current plan as Current plan and disables its CTA', async () => {
    getPublic.mockResolvedValueOnce(PLAN_FIXTURE)
    useBillingStore.setState({
      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,
      },
      planBilling: null,
      planLimits: {},
      enabledFeatures: {},
      isLoading: false,
      error: null,
    })

    renderPage()
    await waitFor(() => {
      expect(screen.getByTestId('plan-current-pro')).toBeInTheDocument()
    })
    const cta = screen.getByTestId('plan-cta-pro') as HTMLButtonElement
    expect(cta).toBeDisabled()
  })
})
