import React, { useCallback, useEffect, useRef, useState } from 'react'
import {
  type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
  logEvent,
} from 'src/services/analytics/index.js'
import { KeyboardShortcutHint } from '../../components/design-system/KeyboardShortcutHint.js'
import { Spinner } from '../../components/Spinner.js'
import TextInput from '../../components/TextInput.js'
import { useTerminalSize } from '../../hooks/useTerminalSize.js'
import type { KeyboardEvent } from '../../ink/events/keyboard-event.js'
import { setClipboard } from '../../ink/termio/osc.js'
import { Box, Link, Text } from '../../ink.js'
import { useCloudOAuthCallbackOnly } from '../../constants/oauth.js'
import { OAuthService } from '../../services/oauth/index.js'
import { saveOAuthTokensIfNeeded } from '../../utils/auth.js'
import { logError } from '../../utils/log.js'
import { parseOAuthManualPaste } from '../../utils/oauthManualPaste.js'

const PASTE_HERE_MSG = 'Paste callback URL here > '

interface OAuthFlowStepProps {
  onSuccess: (token: string) => void
  onCancel: () => void
}
type OAuthStatus =
  | { state: 'starting' }
  | { state: 'waiting_for_login'; url: string }
  | { state: 'processing' }
  | { state: 'success'; token: string }
  | { state: 'error'; message: string; toRetry?: OAuthStatus }
  | { state: 'about_to_retry'; nextState: OAuthStatus }

export function OAuthFlowStep({
  onSuccess,
  onCancel,
}: OAuthFlowStepProps): React.ReactNode {
  const cloudOAuthOnly = useCloudOAuthCallbackOnly()
  const [oauthStatus, setOAuthStatus] = useState<OAuthStatus>({
    state: 'starting',
  })
  const [oauthService] = useState(() => new OAuthService())
  const [pastedCode, setPastedCode] = useState('')
  const [cursorOffset, setCursorOffset] = useState(0)
  const [urlCopied, setUrlCopied] = useState(false)
  const timersRef = useRef<Set<NodeJS.Timeout>>(new Set())
  const urlCopiedTimerRef = useRef<NodeJS.Timeout | undefined>(undefined)
  const terminalSize = useTerminalSize()
  const textInputColumns = Math.max(
    50,
    terminalSize.columns - PASTE_HERE_MSG.length - 4,
  )

  useEffect(() => {
    if (
      pastedCode === 'c' &&
      oauthStatus.state === 'waiting_for_login' &&
      !urlCopied
    ) {
      void setClipboard(oauthStatus.url).then(raw => {
        if (raw) process.stdout.write(raw)
        setUrlCopied(true)
        clearTimeout(urlCopiedTimerRef.current)
        urlCopiedTimerRef.current = setTimeout(setUrlCopied, 2000, false)
      })
      setPastedCode('')
    }
  }, [pastedCode, oauthStatus, urlCopied])

  function handleKeyDown(e: KeyboardEvent): void {
    if (oauthStatus.state !== 'error') return
    e.preventDefault()
    if (e.key === 'return' && oauthStatus.toRetry) {
      setPastedCode('')
      setCursorOffset(0)
      setOAuthStatus({
        state: 'about_to_retry',
        nextState: oauthStatus.toRetry,
      })
    } else {
      onCancel()
    }
  }

  async function handleSubmitCode(value: string, url: string) {
    try {
      const parsed = parseOAuthManualPaste(value)
      if (!parsed) {
        const v = value.trim()
        const looksLikeSignInLink =
          /[?&]code=true\b/.test(v) && /[?&]client_id=/.test(v)
        const stuckOnIndexAfterLogin =
          looksLikeSignInLink && /index\.html/i.test(v)
        setOAuthStatus({
          state: 'error',
          message: looksLikeSignInLink
            ? stuckOnIndexAfterLogin
              ? '登录后若仍是 index.html?code=true…，环回未成功。请在 shell 执行 export RIOS_OAUTH_USE_CLOUD_CALLBACK=1，或在 .env 中写入 RIOS_OAUTH_USE_CLOUD_CALLBACK=1，重启后再登录，并粘贴 …/oauth/code/callback?code=… 整段 URL。'
              : '这是授权入口（code=true），不是回调。请粘贴 /callback?code= 或 /oauth/code/callback?code= 且 code 为一长串的完整地址。'
            : 'Invalid callback. Paste the full browser URL (with ?code= and &state=).',
          toRetry: { state: 'waiting_for_login', url },
        })
        return
      }
      logEvent('tengu_oauth_manual_entry', {})
      oauthService.handleManualAuthCodeInput({
        authorizationCode: parsed.authorizationCode,
        state: parsed.state,
        useManualRedirectForTokenExchange:
          parsed.useManualRedirectForTokenExchange,
      })
    } catch (err: unknown) {
      logError(err as Error)
      setOAuthStatus({
        state: 'error',
        message: (err as Error).message,
        toRetry: { state: 'waiting_for_login', url },
      })
    }
  }

  const startOAuth = useCallback(async () => {
    timersRef.current.forEach(timer => clearTimeout(timer))
    timersRef.current.clear()
    try {
      const result = await oauthService.startOAuthFlow(
        async automaticUrl => {
          setOAuthStatus({
            state: 'waiting_for_login',
            url: automaticUrl,
          })
        },
        {
          loginWithClaudeAi: true,
          inferenceOnly: true,
          expiresIn: 365 * 24 * 60 * 60,
        },
      )

      setOAuthStatus({
        state: 'processing',
      })

      saveOAuthTokensIfNeeded(result)

      const timer1 = setTimeout(
        (
          setOAuthStatus_0,
          accessToken,
          onSuccess_0,
          timersRef_0: React.MutableRefObject<Set<NodeJS.Timeout>>,
        ) => {
          setOAuthStatus_0({
            state: 'success',
            token: accessToken,
          })
          const timer2 = setTimeout(onSuccess_0, 1000, accessToken)
          timersRef_0.current.add(timer2)
        },
        100,
        setOAuthStatus,
        result.accessToken,
        onSuccess,
        timersRef,
      )
      timersRef.current.add(timer1)
    } catch (err_0) {
      const errorMessage = (err_0 as Error).message
      setOAuthStatus({
        state: 'error',
        message: errorMessage,
        toRetry: {
          state: 'starting',
        },
      })
      logError(err_0)
      logEvent('tengu_oauth_error', {
        error:
          errorMessage as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
      })
    }
  }, [oauthService, onSuccess])

  useEffect(() => {
    if (oauthStatus.state === 'starting') {
      void startOAuth()
    }
  }, [oauthStatus.state, startOAuth])

  useEffect(() => {
    if (oauthStatus.state === 'about_to_retry') {
      const timer_1 = setTimeout(nextState => {
        setOAuthStatus(nextState)
      }, 500, oauthStatus.nextState)
      timersRef.current.add(timer_1)
    }
  }, [oauthStatus])

  useEffect(() => {
    const timers = timersRef.current
    return () => {
      oauthService.cleanup()
      timers.forEach(timer_2 => clearTimeout(timer_2))
      timers.clear()
      clearTimeout(urlCopiedTimerRef.current)
    }
  }, [oauthService])

  function renderStatusMessage(): React.ReactNode {
    switch (oauthStatus.state) {
      case 'starting':
        return (
          <Box>
            <Spinner />
            <Text>Starting authentication…</Text>
          </Box>
        )
      case 'waiting_for_login':
        return (
          <Box flexDirection="column" gap={1}>
            <Box>
              <Spinner />
              <Text>
                {cloudOAuthOnly
                  ? 'Open browser — then paste the callback URL below.'
                  : 'Waiting for loopback redirect — or paste the callback URL below.'}
              </Text>
            </Box>
            <Box flexDirection="column" gap={1}>
              <Box>
                <Text>{PASTE_HERE_MSG}</Text>
                <TextInput
                  value={pastedCode}
                  onChange={setPastedCode}
                  onSubmit={v => handleSubmitCode(v, oauthStatus.url)}
                  cursorOffset={cursorOffset}
                  onChangeCursorOffset={setCursorOffset}
                  columns={textInputColumns}
                  mask="*"
                />
              </Box>
              <Box paddingX={1}>
                <Text dimColor>
                  <KeyboardShortcutHint
                    shortcut="c"
                    action="copy link"
                    parens
                  />
                </Text>
              </Box>
            </Box>
          </Box>
        )
      case 'processing':
        return (
          <Box>
            <Spinner />
            <Text>Processing authentication…</Text>
          </Box>
        )
      case 'success':
        return (
          <Box flexDirection="column" gap={1}>
            <Text color="success">
              ✓ Authentication token created successfully!
            </Text>
            <Text dimColor>Using token for GitHub Actions setup…</Text>
          </Box>
        )
      case 'error': {
        const isPasteCallbackHint =
          oauthStatus.message.includes('RIOS_OAUTH_USE_CLOUD_CALLBACK') ||
          oauthStatus.message.includes('授权入口（code=true）')
        return (
          <Box flexDirection="column" gap={1}>
            <Text
              color={isPasteCallbackHint ? 'warning' : 'error'}
            >
              {isPasteCallbackHint
                ? `无法使用当前链接：\n${oauthStatus.message}`
                : `OAuth error: ${oauthStatus.message}`}
            </Text>
            {oauthStatus.toRetry ? (
              <Text dimColor>
                Press Enter to try again, or any other key to cancel
              </Text>
            ) : (
              <Text dimColor>Press any key to return to API key selection</Text>
            )}
          </Box>
        )
      }
      case 'about_to_retry':
        return (
          <Box flexDirection="column" gap={1}>
            <Text color="permission">Retrying…</Text>
          </Box>
        )
      default:
        return null
    }
  }

  return (
    <Box
      flexDirection="column"
      gap={1}
      tabIndex={0}
      autoFocus
      onKeyDown={handleKeyDown}
    >
      {oauthStatus.state === 'starting' && (
        <Box flexDirection="column" gap={1} paddingBottom={1}>
          <Text bold>Create Authentication Token</Text>
          <Text dimColor>Creating a long-lived token for GitHub Actions</Text>
        </Box>
      )}
      {oauthStatus.state !== 'success' &&
        oauthStatus.state !== 'starting' &&
        oauthStatus.state !== 'processing' && (
          <Box
            key="header"
            flexDirection="column"
            gap={1}
            paddingBottom={1}
          >
            <Text bold>Create Authentication Token</Text>
            <Text dimColor>Creating a long-lived token for GitHub Actions</Text>
          </Box>
        )}
      {oauthStatus.state === 'waiting_for_login' && (
        <Box
          flexDirection="column"
          key="oauthOpenHint"
          gap={1}
          paddingBottom={1}
        >
          <Box paddingX={1}>
            <Text dimColor>
              {cloudOAuthOnly ? (
                <>
                  Set RIOS_OAUTH_USE_CLOUD_CALLBACK=0 to try automatic loopback.
                  Otherwise, after login copy the full address bar URL and paste
                  below.
                </>
              ) : (
                <>
                  Complete sign-in in the browser; RiOS Code continues when the
                  redirect hits 127.0.0.1. If that never happens, paste the full
                  callback URL below (no restart), or set RIOS_OAUTH_USE_CLOUD_CALLBACK=1
                  for paste-only mode.
                </>
              )}
            </Text>
          </Box>
          <Link url={oauthStatus.url}>
            <Text dimColor>{oauthStatus.url}</Text>
          </Link>
        </Box>
      )}
      <Box paddingLeft={1} flexDirection="column" gap={1}>
        {renderStatusMessage()}
      </Box>
    </Box>
  )
}
