import { describe, it, expect, beforeEach, vi } from 'vitest'
import { render, screen, waitFor } from '@testing-library/react'
import { BrowserRouter } from 'react-router-dom'
import { NextStepCard, pickNextStep } from '../NextStepCard'
import { useBillingStore } from '@/store/billingStore'
import type { OnboardingStatus } from '@/api/onboarding'

vi.mock('@/api/onboarding', () => {
  const mockGet = vi.fn()
  const mockDismiss = vi.fn()
  return {
    getOnboardingStatus: mockGet,
    dismissOnboarding: mockDismiss,
  }
})

import {
  getOnboardingStatus as _getOnboardingStatus,
} from '@/api/onboarding'

const getOnboardingStatus = _getOnboardingStatus as unknown as ReturnType<typeof vi.fn>

function makeStatus(overrides: Partial<OnboardingStatus> = {}): OnboardingStatus {
  return {
    created_flow: false,
    ran_session: false,
    exported_session: false,
    tried_ai_assistant: false,
    invited_teammate: false,
    connected_psa: false,
    is_team_user: false,
    dismissed: false,
    email_verified: false,
    shop_setup_done: false,
    ...overrides,
  }
}

function renderWithRouter(ui: React.ReactElement) {
  return render(<BrowserRouter>{ui}</BrowserRouter>)
}

function setBillingComplimentary() {
  // 'complimentary' status -> stage 'complimentary' (not in plan-gate set), so the
  // "Pick a plan" item stays hidden — perfect default for unrelated tests.
  useBillingStore.setState({
    subscription: {
      status: 'complimentary',
      plan: 'pro',
      current_period_start: '2026-05-01T00:00:00Z',
      current_period_end: null,
      cancel_at_period_end: false,
      seat_limit: null,
      has_pro_entitlement: true,
      is_paid: true,
    },
    planBilling: null,
    planLimits: {},
    enabledFeatures: {},
    isLoading: false,
    error: null,
  })
}

describe('NextStepCard', () => {
  beforeEach(() => {
    getOnboardingStatus.mockReset()
    setBillingComplimentary()
  })

  it('renders Verify your email when email unverified', async () => {
    getOnboardingStatus.mockResolvedValue(makeStatus({ email_verified: false }))
    renderWithRouter(<NextStepCard />)
    await waitFor(() => {
      expect(screen.getByTestId('next-step-card')).toBeInTheDocument()
    })
    expect(screen.getByRole('heading', { name: /Verify your email/i })).toBeInTheDocument()
  })

  it('renders Set up your shop after email verified', async () => {
    getOnboardingStatus.mockResolvedValue(
      makeStatus({ email_verified: true, shop_setup_done: false }),
    )
    renderWithRouter(<NextStepCard />)
    await waitFor(() => {
      expect(screen.getByRole('heading', { name: /Set up your shop/i })).toBeInTheDocument()
    })
  })

  it('renders Run your first FlowPilot session after shop setup', async () => {
    getOnboardingStatus.mockResolvedValue(
      makeStatus({
        email_verified: true,
        shop_setup_done: true,
        ran_session: false,
      }),
    )
    renderWithRouter(<NextStepCard />)
    await waitFor(() => {
      expect(
        screen.getByRole('heading', { name: /Run your first FlowPilot session/i }),
      ).toBeInTheDocument()
    })
  })

  it('hidden when all items done', async () => {
    getOnboardingStatus.mockResolvedValue(
      makeStatus({
        email_verified: true,
        shop_setup_done: true,
        ran_session: true,
        connected_psa: true,
        invited_teammate: true,
      }),
    )
    const { container } = renderWithRouter(<NextStepCard />)
    // Resolve the awaited promise.
    await waitFor(() => expect(getOnboardingStatus).toHaveBeenCalled())
    expect(container.querySelector('[data-testid="next-step-card"]')).toBeNull()
  })

  it('hidden when onboarding_dismissed', async () => {
    getOnboardingStatus.mockResolvedValue(makeStatus({ dismissed: true }))
    const { container } = renderWithRouter(<NextStepCard />)
    await waitFor(() => expect(getOnboardingStatus).toHaveBeenCalled())
    expect(container.querySelector('[data-testid="next-step-card"]')).toBeNull()
  })

  it('Pick a plan item appears when trial stage is warning or later', () => {
    // Direct unit-test on the pure picker — easier than coordinating both the
    // billing store + the network mock + a fake clock for stage='warning'.
    const allDoneExceptPlan = makeStatus({
      email_verified: true,
      shop_setup_done: true,
      ran_session: true,
      connected_psa: true,
      invited_teammate: true,
    })

    expect(pickNextStep(allDoneExceptPlan, 'pristine')).toBeNull()
    expect(pickNextStep(allDoneExceptPlan, 'paid')).toBeNull()
    expect(pickNextStep(allDoneExceptPlan, 'complimentary')).toBeNull()

    expect(pickNextStep(allDoneExceptPlan, 'warning')?.key).toBe('pick_plan')
    expect(pickNextStep(allDoneExceptPlan, 'urgent')?.key).toBe('pick_plan')
    expect(pickNextStep(allDoneExceptPlan, 'expired')?.key).toBe('pick_plan')
  })
})
