// @vitest-environment happy-dom
import { describe, expect, it, vi } from 'vitest'
import { fireEvent, render, screen } from '@testing-library/react'
import {
  OnboardingBlock,
  deriveOnboardingSteps,
  shouldShowOnboarding,
  type OnboardingSignals,
} from '../../views/dashboard/OnboardingBlock.js'

function signals(over: Partial<OnboardingSignals> = {}): OnboardingSignals {
  return {
    postsAndPagesCount: 0,
    mediaCount: 0,
    seoScore: 0,
    userCount: 1,
    hasApiTraffic: false,
    ...over,
  }
}

describe('deriveOnboardingSteps', () => {
  it('marks only the workspace step done on a brand-new site', () => {
    const steps = deriveOnboardingSteps(signals())
    expect(steps).toHaveLength(6)
    expect(steps.filter((s) => s.done).map((s) => s.id)).toEqual(['workspace'])
  })

  it('derives each step from its dashboard signal', () => {
    const steps = deriveOnboardingSteps(
      signals({
        postsAndPagesCount: 3,
        mediaCount: 2,
        seoScore: 71,
        userCount: 4,
        hasApiTraffic: true,
      }),
    )
    expect(steps.every((s) => s.done)).toBe(true)
  })

  it('treats a lone user and zero SEO score as incomplete steps', () => {
    const steps = deriveOnboardingSteps(signals({ userCount: 1, seoScore: 0 }))
    const byId = Object.fromEntries(steps.map((s) => [s.id, s.done]))
    expect(byId['invite']).toBe(false)
    expect(byId['seo']).toBe(false)
    expect(byId['api-key']).toBe(false)
  })
})

describe('shouldShowOnboarding', () => {
  it('shows only when both posts+pages and media are empty', () => {
    expect(shouldShowOnboarding(signals())).toBe(true)
    expect(shouldShowOnboarding(signals({ postsAndPagesCount: 1 }))).toBe(false)
    expect(shouldShowOnboarding(signals({ mediaCount: 1 }))).toBe(false)
  })
})

describe('OnboardingBlock', () => {
  it('renders the welcome banner with the derived progress count', () => {
    render(<OnboardingBlock signals={signals()} onNavigate={() => {}} />)

    expect(screen.getByText(/Welcome to ActuateCMS/)).toBeTruthy()
    // 1 of 6 done (workspace only) on a fresh site.
    expect(screen.getByText(/1\/6 steps complete/)).toBeTruthy()

    const bar = screen.getByRole('progressbar', { name: 'Onboarding progress' })
    expect(bar.getAttribute('aria-valuenow')).toBe('1')
    expect(bar.getAttribute('aria-valuemax')).toBe('6')
  })

  it('updates the progress count as steps derive complete', () => {
    render(
      <OnboardingBlock signals={signals({ userCount: 3, seoScore: 50 })} onNavigate={() => {}} />,
    )

    expect(screen.getByText(/3\/6 steps complete/)).toBeTruthy()
    expect(
      screen
        .getByRole('progressbar', { name: 'Onboarding progress' })
        .getAttribute('aria-valuenow'),
    ).toBe('3')
  })

  it('renders all six checklist labels with accessible completion state', () => {
    render(<OnboardingBlock signals={signals()} onNavigate={() => {}} />)

    for (const label of [
      'Create your workspace',
      'Create your first Post or Page',
      'Upload media assets',
      'Configure SEO defaults',
      'Get your API key',
      'Invite team members',
    ]) {
      expect(screen.getByText(label)).toBeTruthy()
    }

    // Completion is announced via text, not color alone.
    expect(screen.getAllByText('(completed)')).toHaveLength(1)
    expect(screen.getAllByText('(not completed)')).toHaveLength(5)
  })

  it('navigates through quick links via onNavigate', () => {
    const onNavigate = vi.fn()
    render(<OnboardingBlock signals={signals()} onNavigate={onNavigate} />)

    fireEvent.click(screen.getByRole('button', { name: /Invite team/ }))
    expect(onNavigate).toHaveBeenCalledWith('/settings?tab=users')

    fireEvent.click(screen.getByRole('button', { name: /API Reference/ }))
    expect(onNavigate).toHaveBeenCalledWith('/settings?tab=api-keys')

    fireEvent.click(screen.getByRole('button', { name: /SEO defaults/ }))
    expect(onNavigate).toHaveBeenCalledWith('/settings?tab=seo')
  })
})

// ── Dashboard integration: visibility rule ─────────────────────────────────

const responses: Record<string, unknown> = {}
const emptyResult = { data: null, loading: false, error: null, exhausted: false, refetch: () => {} }

vi.mock('../../lib/useApiData.js', () => ({
  useApiData: (endpoint: string | null) => responses[endpoint ?? ''] ?? emptyResult,
}))

const { Dashboard } = await import('../../views/Dashboard.js')

const baseStats = {
  totalDocuments: 0,
  totalMedia: 0,
  totalUsers: 1,
  formCount: 0,
  avgSeoScore: 0,
  webhookCount: 0,
  webhookActiveCount: 0,
  collectionCounts: {} as Record<string, number>,
  statusCounts: {},
  recentDocuments: [] as unknown[],
}

function statsResult(over: Partial<typeof baseStats> = {}) {
  return {
    data: { ...baseStats, ...over },
    loading: false,
    error: null,
    exhausted: false,
    refetch: () => {},
  }
}

describe('Dashboard onboarding visibility', () => {
  it('replaces the activity grid with onboarding when the site is empty', () => {
    responses['/stats'] = statsResult()

    render(<Dashboard config={{ collections: [] }} session={{}} onNavigate={() => {}} />)

    expect(screen.getByText(/Welcome to ActuateCMS/)).toBeTruthy()
    expect(screen.queryByText('Recent Activity')).toBeNull()
    expect(screen.queryByText('Publishing Queue')).toBeNull()
    expect(screen.queryByText('Content Health')).toBeNull()
    // The Delivery API card below the block stays.
    expect(screen.getByText('Delivery API')).toBeTruthy()
    delete responses['/stats']
  })

  it('renders the normal dashboard when posts or pages exist', () => {
    responses['/stats'] = statsResult({ collectionCounts: { posts: 2 } })

    render(
      <Dashboard
        config={{ collections: [{ slug: 'posts', type: 'post' }] }}
        session={{}}
        onNavigate={() => {}}
      />,
    )

    expect(screen.queryByText(/Welcome to ActuateCMS/)).toBeNull()
    expect(screen.getByText('Recent Activity')).toBeTruthy()
    delete responses['/stats']
  })

  it('renders the normal dashboard when only media exists', () => {
    responses['/stats'] = statsResult({ totalMedia: 5 })

    render(<Dashboard config={{ collections: [] }} session={{}} onNavigate={() => {}} />)

    expect(screen.queryByText(/Welcome to ActuateCMS/)).toBeNull()
    expect(screen.getByText('Recent Activity')).toBeTruthy()
    delete responses['/stats']
  })
})
