import { describe, it, expect, vi, beforeEach } from 'vitest'
import { renderHook } from '@testing-library/react'
import { useTelemetry } from './useTelemetry'
import type { Settings } from '../types'

const mockInitSentry = vi.fn()
const mockTeardownSentry = vi.fn()
const mockInitPostHog = vi.fn()
const mockTeardownPostHog = vi.fn()
const mockUpdatePostHogIdentify = vi.fn()
const mockSetReleaseChannel = vi.fn()

vi.mock('../lib/telemetry', () => ({
  initSentry: (...args: unknown[]) => mockInitSentry(...args),
  teardownSentry: () => mockTeardownSentry(),
  initPostHog: (...args: unknown[]) => mockInitPostHog(...args),
  teardownPostHog: () => mockTeardownPostHog(),
  updatePostHogIdentify: (...args: unknown[]) => mockUpdatePostHogIdentify(...args),
  setReleaseChannel: (...args: unknown[]) => mockSetReleaseChannel(...args),
}))

const baseSettings: Settings = {
  auto_pull_interval_minutes: null,
  telemetry_consent: null, crash_reporting_enabled: null,
  analytics_enabled: null, anonymous_id: null, release_channel: null,
}

function renderTelemetry(settings: Settings, loaded = true) {
  return renderHook(() => useTelemetry(settings, loaded))
}

function analyticsSettings(releaseChannel: string | null = null): Settings {
  return {
    ...baseSettings,
    analytics_enabled: true,
    anonymous_id: 'test-uuid',
    release_channel: releaseChannel,
  }
}

describe('useTelemetry', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })

  it('does nothing when settings are not loaded', () => {
    renderTelemetry(baseSettings, false)
    expect(mockInitSentry).not.toHaveBeenCalled()
    expect(mockInitPostHog).not.toHaveBeenCalled()
  })

  it('does nothing when consent is not granted', () => {
    renderTelemetry({ ...baseSettings, telemetry_consent: false })
    expect(mockInitSentry).not.toHaveBeenCalled()
    expect(mockInitPostHog).not.toHaveBeenCalled()
  })

  it('initializes Sentry when crash reporting is enabled', () => {
    renderTelemetry({ ...baseSettings, crash_reporting_enabled: true, anonymous_id: 'test-uuid' })
    expect(mockInitSentry).toHaveBeenCalledWith('test-uuid')
  })

  it.each([
    { name: 'stable defaults', releaseChannel: null, expectedChannel: 'stable' },
    { name: 'legacy beta release channels', releaseChannel: 'beta', expectedChannel: 'stable' },
  ])('initializes PostHog for $name', ({ releaseChannel, expectedChannel }) => {
    renderTelemetry(analyticsSettings(releaseChannel))

    expect(mockInitPostHog).toHaveBeenCalledWith('test-uuid', expectedChannel)
    expect(mockSetReleaseChannel).toHaveBeenCalledWith(expectedChannel)
  })

  it('tears down Sentry when crash reporting is disabled after being enabled', () => {
    const settings1 = { ...baseSettings, crash_reporting_enabled: true, anonymous_id: 'test-uuid' }
    const { rerender } = renderHook(
      ({ settings, loaded }) => useTelemetry(settings, loaded),
      { initialProps: { settings: settings1, loaded: true } }
    )
    expect(mockInitSentry).toHaveBeenCalledOnce()

    const settings2 = { ...baseSettings, crash_reporting_enabled: false, anonymous_id: 'test-uuid' }
    rerender({ settings: settings2, loaded: true })
    expect(mockTeardownSentry).toHaveBeenCalledOnce()
  })

  it('does not initialize without anonymous_id', () => {
    renderTelemetry({ ...baseSettings, crash_reporting_enabled: true, anonymous_id: null })
    expect(mockInitSentry).not.toHaveBeenCalled()
  })

  it('updates the analytics identity when the normalized channel changes', () => {
    const { rerender } = renderHook(
      ({ settings, loaded }) => useTelemetry(settings, loaded),
      {
        initialProps: {
          settings: {
            ...baseSettings,
            analytics_enabled: true,
            anonymous_id: 'test-uuid',
            release_channel: 'alpha',
          },
          loaded: true,
        },
      },
    )

    rerender({
      settings: {
        ...baseSettings,
        analytics_enabled: true,
        anonymous_id: 'test-uuid',
        release_channel: 'beta',
      },
      loaded: true,
    })

    expect(mockUpdatePostHogIdentify).toHaveBeenCalledWith('stable')
  })
})
