import React, { useCallback, useEffect, useRef } from 'react'
import { Box, Text } from '@anthropic/ink'
import {
  isMaxSubscriber,
  isProSubscriber,
  isTeamSubscriber,
} from '../utils/auth.js'
import { getGlobalConfig, saveGlobalConfig } from '../utils/config.js'
import type { EffortLevel } from '../utils/effort.js'
import {
  convertEffortValueToLevel,
  getDefaultEffortForModel,
  getOpusDefaultEffortConfig,
  toPersistableEffort,
} from '../utils/effort.js'
import { parseUserSpecifiedModel } from '../utils/model/model.js'
import { updateSettingsForSource } from '../utils/settings/settings.js'
import type { OptionWithDescription } from './CustomSelect/select.js'
import { Select } from './CustomSelect/select.js'
import { effortLevelToSymbol } from './EffortIndicator.js'
import { PermissionDialog } from './permissions/PermissionDialog.js'

type EffortCalloutSelection = EffortLevel | undefined | 'dismiss'

type Props = {
  model: string
  onDone: (selection: EffortCalloutSelection) => void
}

const AUTO_DISMISS_MS = 30_000

export function EffortCallout({ model, onDone }: Props): React.ReactNode {
  const defaultEffortConfig = getOpusDefaultEffortConfig()
  // Latest-ref pattern — write via effect so React Compiler can memoize.
  const onDoneRef = useRef(onDone)
  useEffect(() => {
    onDoneRef.current = onDone
  })

  const handleCancel = useCallback((): void => {
    onDoneRef.current('dismiss')
  }, [])

  // Permanently dismiss on mount so it only shows once
  useEffect(() => {
    markV2Dismissed()
  }, [])

  // 30-second auto-dismiss timer
  useEffect(() => {
    const timeoutId = setTimeout(handleCancel, AUTO_DISMISS_MS)
    return () => clearTimeout(timeoutId)
  }, [handleCancel])

  const defaultEffort = getDefaultEffortForModel(model)
  const defaultLevel = defaultEffort
    ? convertEffortValueToLevel(defaultEffort)
    : 'high'

  const handleSelect = useCallback(
    (value: EffortLevel): void => {
      const effortLevel = value === defaultLevel ? undefined : value
      updateSettingsForSource('userSettings', {
        effortLevel: toPersistableEffort(effortLevel),
      })
      onDoneRef.current(value)
    },
    [defaultLevel],
  )

  const options: OptionWithDescription<EffortLevel>[] = [
    {
      label: <EffortOptionLabel level="medium" text="Medium (recommended)" />,
      value: 'medium',
    },
    { label: <EffortOptionLabel level="high" text="High" />, value: 'high' },
    { label: <EffortOptionLabel level="low" text="Low" />, value: 'low' },
  ]

  return (
    <PermissionDialog title={defaultEffortConfig.dialogTitle}>
      <Box flexDirection="column" paddingX={2} paddingY={1}>
        <Box marginBottom={1} flexDirection="column">
          <Text>{defaultEffortConfig.dialogDescription}</Text>
        </Box>
        <Box marginBottom={1}>
          <Text dimColor>
            <EffortIndicatorSymbol level="low" /> low {'·'}{' '}
            <EffortIndicatorSymbol level="medium" /> medium {'·'}{' '}
            <EffortIndicatorSymbol level="high" /> high
          </Text>
        </Box>
        <Select
          options={options}
          onChange={handleSelect}
          onCancel={handleCancel}
        />
      </Box>
    </PermissionDialog>
  )
}

function EffortIndicatorSymbol({
  level,
}: {
  level: EffortLevel
}): React.ReactNode {
  return <Text color="suggestion">{effortLevelToSymbol(level)}</Text>
}

function EffortOptionLabel({
  level,
  text,
}: {
  level: EffortLevel
  text: string
}): React.ReactNode {
  return (
    <>
      <EffortIndicatorSymbol level={level} /> {text}
    </>
  )
}

/**
 * Check whether to show the effort callout.
 *
 * Audience:
 * - Pro: already had medium default; show unless they saw v1 (effortCalloutDismissed)
 * - Max/Team: getting medium via tengu_grey_step2 config; show when enabled
 * - Everyone else: mark as dismissed so it never shows
 */
export function shouldShowEffortCallout(model: string): boolean {
  // Only show for Opus 4.6 for now
  const parsed = parseUserSpecifiedModel(model)
  if (!parsed.toLowerCase().includes('opus-4-6')) {
    return false
  }

  const config = getGlobalConfig()
  if (config.effortCalloutV2Dismissed) return false

  // Don't show to brand-new users — they never knew the old default, so this
  // isn't a change for them. Mark as dismissed so it stays suppressed.
  if (config.numStartups <= 1) {
    markV2Dismissed()
    return false
  }

  // Pro users already had medium default before this PR. Show the new copy,
  // but skip if they already saw the v1 dialog — no point nagging twice.
  if (isProSubscriber()) {
    if (config.effortCalloutDismissed) {
      markV2Dismissed()
      return false
    }
    return getOpusDefaultEffortConfig().enabled
  }

  // Max/Team are the target of the tengu_grey_step2 config.
  // Don't mark dismissed when config is disabled — they should see the dialog
  // once it's enabled for them.
  if (isMaxSubscriber() || isTeamSubscriber()) {
    return getOpusDefaultEffortConfig().enabled
  }

  // Everyone else (free tier, API key, non-subscribers): not in scope.
  markV2Dismissed()
  return false
}

function markV2Dismissed(): void {
  saveGlobalConfig(current => {
    if (current.effortCalloutV2Dismissed) return current
    return { ...current, effortCalloutV2Dismissed: true }
  })
}
