import { memo, useCallback, useEffect, useRef, type CSSProperties, type ReactNode } from 'react'
import { Sparkle, X, PaperPlaneRight, Plus, Link, Stop } from '@phosphor-icons/react'
import { AiMessage } from './AiMessage'
import { Button } from '@/components/ui/button'
import { ActionTooltip } from '@/components/ui/action-tooltip'
import { TooltipProvider } from '@/components/ui/tooltip'
import { WikilinkChatInput } from './WikilinkChatInput'
import { extractInlineWikilinkReferences } from './inlineWikilinkText'
import {
  aiAgentPermissionModeLabels,
  type AiAgentPermissionMode,
} from '../lib/aiAgentPermissionMode'
import { createTranslator, type AppLocale } from '../lib/i18n'
import type { AiAgentMessage } from '../hooks/useCliAiAgent'
import type { AiAgentReadiness } from '../lib/aiAgents'
import type { NoteReference } from '../utils/ai-context'
import type { VaultEntry } from '../types'
import { cn } from '@/lib/utils'

interface AiPanelHeaderProps {
  agentLabel: string
  agentReadiness: AiAgentReadiness
  targetKind?: 'agent' | 'api_model'
  locale?: AppLocale
  permissionMode: AiAgentPermissionMode
  permissionModeDisabled: boolean
  onPermissionModeChange: (mode: AiAgentPermissionMode) => void
  onClose: () => void
  onNewChat: () => void
}

interface AiPanelContextBarProps {
  activeEntry: VaultEntry
  locale?: AppLocale
  linkedCount: number
}

interface AiPanelMessageHistoryProps {
  agentLabel: string
  agentReadiness: AiAgentReadiness
  locale?: AppLocale
  messages: AiAgentMessage[]
  isActive: boolean
  onForkMessage?: (messageId: string) => void
  onOpenNote?: (path: string) => void
  onNavigateWikilink?: (target: string) => void
  onRegenerateMessage?: (messageId: string) => void
  onScrollStateChange?: (scrolled: boolean) => void
  hasContext: boolean
}

interface AiPanelComposerProps {
  entries: VaultEntry[]
  agentLabel: string
  agentReadiness: AiAgentReadiness
  locale?: AppLocale
  input: string
  inputRef: React.RefObject<HTMLDivElement | null>
  isActive: boolean
  controls?: ReactNode
  onChange: (value: string) => void
  onSend: (text: string, references: NoteReference[]) => void
  onStop: () => void
  onUnsupportedAiPaste?: (message: string) => void
}

function getComposerPlaceholder(
  agentLabel: string,
  agentReadiness: AiAgentReadiness,
  t: ReturnType<typeof createTranslator>,
): string {
  if (agentReadiness === 'checking') {
    return t('ai.panel.placeholder.checking')
  }

  if (agentReadiness === 'missing') {
    return t('ai.panel.placeholder.missing', { agent: agentLabel })
  }

  return t('ai.panel.placeholder.ready', { agent: agentLabel })
}

function composerSendButtonStyle(canSend: boolean): CSSProperties {
  return {
    background: canSend ? 'var(--primary)' : 'var(--muted)',
    color: canSend ? 'var(--primary-foreground)' : 'var(--muted-foreground)',
    borderRadius: 8,
    width: 30,
    height: 30,
    cursor: canSend ? 'pointer' : 'not-allowed',
  }
}

function composerStopButtonStyle(): CSSProperties {
  return {
    background: 'var(--destructive)',
    color: 'var(--destructive-foreground)',
    borderRadius: 8,
    width: 30,
    height: 30,
    cursor: 'pointer',
  }
}

function ComposerInput({
  disabled,
  entries,
  hasControls,
  input,
  inputRef,
  onChange,
  onSend,
  onUnsupportedAiPaste,
  placeholder,
}: {
  disabled: boolean
  entries: VaultEntry[]
  hasControls: boolean
  input: string
  inputRef: React.RefObject<HTMLDivElement | null>
  onChange: (value: string) => void
  onSend: (text: string, references: NoteReference[]) => void
  onUnsupportedAiPaste?: (message: string) => void
  placeholder: string
}) {
  return (
    <WikilinkChatInput
      entries={entries}
      value={input}
      onChange={onChange}
      onSend={onSend}
      onUnsupportedPaste={onUnsupportedAiPaste}
      disabled={disabled}
      placeholder={placeholder}
      placeholderClassName={hasControls ? 'px-2 py-1.5 text-[13px] leading-5' : undefined}
      inputRef={inputRef}
      editorClassName={cn(
        'max-h-[120px] overflow-y-auto overscroll-contain',
        hasControls && 'min-h-[34px] border-0 px-2 py-1.5 leading-5',
      )}
      editorStyle={{ maxHeight: 120, overflowY: 'auto', overscrollBehavior: 'contain' }}
    />
  )
}

function ComposerSendButton({
  canSend,
  entries,
  input,
  label,
  onSend,
}: {
  canSend: boolean
  entries: VaultEntry[]
  input: string
  label: string
  onSend: (text: string, references: NoteReference[]) => void
}) {
  return (
    <Button
      type="button"
      variant="ghost"
      size="icon-sm"
      className="shrink-0 flex items-center justify-center border-none cursor-pointer transition-colors"
      style={composerSendButtonStyle(canSend)}
      onClick={() => onSend(input, extractInlineWikilinkReferences(input, entries))}
      disabled={!canSend}
      aria-label={label}
      title={label}
      data-testid="agent-send"
    >
      <PaperPlaneRight size={16} />
    </Button>
  )
}

function ComposerStopButton({
  label,
  onStop,
}: {
  label: string
  onStop: () => void
}) {
  return (
    <Button
      type="button"
      variant="ghost"
      size="icon-sm"
      className="shrink-0 flex items-center justify-center border-none cursor-pointer transition-colors hover:opacity-90"
      style={composerStopButtonStyle()}
      onClick={onStop}
      aria-label={label}
      title={label}
      data-testid="agent-stop"
    >
      <Stop size={16} weight="fill" />
    </Button>
  )
}

function ComposerControlsRow({
  children,
  hasControls,
  sendButton,
}: {
  children?: ReactNode
  hasControls: boolean
  sendButton: ReactNode
}) {
  if (!hasControls) return <>{sendButton}</>

  return (
    <div className="mt-0.5 flex items-center justify-between gap-2">
      <div className="flex min-w-0 items-center gap-1">
        {children}
      </div>
      {sendButton}
    </div>
  )
}

function permissionModeTooltip(
  mode: AiAgentPermissionMode,
  t: ReturnType<typeof createTranslator>,
): { label: string } {
  return {
    label: t(mode === 'power_user'
      ? 'ai.permission.powerUser.tooltip'
      : 'ai.permission.safe.tooltip'),
  }
}

function headerStatusText({
  agentLabel,
  agentReadiness,
  modeLabel,
  t,
}: {
  agentLabel: string
  agentReadiness: AiAgentReadiness
  modeLabel: string
  t: ReturnType<typeof createTranslator>
}): string {
  if (agentReadiness === 'checking') return t('ai.panel.status.checking')
  if (agentReadiness === 'missing') return t('ai.panel.status.missing', { agent: agentLabel })
  return t('ai.panel.status.ready', { agent: agentLabel, mode: modeLabel })
}

function AiPanelEmptyState({
  agentLabel,
  agentReadiness,
  hasContext,
  locale = 'en',
}: Pick<AiPanelMessageHistoryProps, 'agentLabel' | 'agentReadiness' | 'hasContext' | 'locale'>) {
  const t = createTranslator(locale)

  if (agentReadiness === 'checking') {
    return (
      <div
        className="flex flex-col items-center justify-center text-center text-muted-foreground"
        style={{ paddingTop: 40 }}
      >
        <Sparkle size={24} style={{ marginBottom: 8, opacity: 0.5 }} />
        <p style={{ fontSize: 13, margin: '0 0 4px' }}>
          {t('ai.panel.empty.checkingTitle')}
        </p>
        <p style={{ fontSize: 11, margin: 0, opacity: 0.6 }}>
          {t('ai.panel.empty.checkingDescription')}
        </p>
      </div>
    )
  }

  if (agentReadiness === 'missing') {
    return (
      <div
        className="flex flex-col items-center justify-center text-center text-muted-foreground"
        style={{ paddingTop: 40 }}
      >
        <Sparkle size={24} style={{ marginBottom: 8, opacity: 0.5 }} />
        <p style={{ fontSize: 13, margin: '0 0 4px' }}>
          {t('ai.panel.empty.missingTitle', { agent: agentLabel })}
        </p>
        <p style={{ fontSize: 11, margin: 0, opacity: 0.6 }}>
          {t('ai.panel.empty.missingDescription')}
        </p>
      </div>
    )
  }

  return (
    <div
      className="flex flex-col items-center justify-center text-center text-muted-foreground"
      style={{ paddingTop: 40 }}
    >
      <Sparkle size={24} style={{ marginBottom: 8, opacity: 0.5 }} />
      <p style={{ fontSize: 13, margin: '0 0 4px' }}>
        {hasContext
          ? t('ai.panel.empty.withContextTitle', { agent: agentLabel })
          : t('ai.panel.empty.noContextTitle', { agent: agentLabel })
        }
      </p>
      <p style={{ fontSize: 11, margin: 0, opacity: 0.6 }}>
        {hasContext
          ? t('ai.panel.empty.withContextDescription')
          : t('ai.panel.empty.noContextDescription')
        }
      </p>
    </div>
  )
}

export const AiPanelHeader = memo(function AiPanelHeader({
  agentLabel,
  agentReadiness,
  targetKind = 'agent',
  locale = 'en',
  permissionMode,
  permissionModeDisabled,
  onPermissionModeChange,
  onClose,
  onNewChat,
}: AiPanelHeaderProps) {
  const t = createTranslator(locale)
  const modeLabel = targetKind === 'api_model'
    ? t('ai.panel.mode.chat')
    : aiAgentPermissionModeLabels(permissionMode, locale).short

  return (
    <div
      className="flex shrink-0 flex-col border-b border-border"
      style={{ padding: '8px 12px', gap: 8 }}
    >
      <div className="flex items-center" style={{ gap: 8 }}>
        <Sparkle size={16} className="shrink-0 text-muted-foreground" />
        <div className="flex flex-1 flex-col overflow-hidden">
          <span className="text-muted-foreground" style={{ fontSize: 13, fontWeight: 600 }}>
            {t('ai.panel.title')}
          </span>
          <span className="truncate text-[11px] text-muted-foreground">
            {headerStatusText({ agentLabel, agentReadiness, modeLabel, t })}
          </span>
        </div>
        <Button
          type="button"
          variant="ghost"
          size="icon-xs"
          className="h-6 w-6 p-0 [&_svg:not([class*=size-])]:size-4"
          onClick={onNewChat}
          aria-label={t('ai.panel.newChat')}
          title={t('ai.panel.newChat')}
        >
          <Plus size={16} />
        </Button>
        <Button
          type="button"
          variant="ghost"
          size="icon-xs"
          className="h-6 w-6 p-0 [&_svg:not([class*=size-])]:size-4"
          onClick={onClose}
          aria-label={t('ai.panel.close')}
          title={t('ai.panel.close')}
        >
          <X size={16} />
        </Button>
      </div>
      {targetKind === 'agent' ? (
        <AiPermissionModeToggle
          value={permissionMode}
          locale={locale}
          disabled={permissionModeDisabled}
          onChange={onPermissionModeChange}
        />
      ) : (
        <div className="rounded-md border border-border bg-muted px-3 py-2 text-[11px] leading-5 text-muted-foreground">
          {t('ai.panel.mode.chatDescription')}
        </div>
      )}
    </div>
  )
})

function AiPermissionModeToggle({
  value,
  locale = 'en',
  disabled,
  onChange,
}: {
  value: AiAgentPermissionMode
  locale?: AppLocale
  disabled: boolean
  onChange: (mode: AiAgentPermissionMode) => void
}) {
  const t = createTranslator(locale)

  return (
    <TooltipProvider>
      <div
        className="inline-flex w-full rounded-md border border-border bg-muted p-1"
        role="radiogroup"
        aria-label={t('ai.permission.modeAria')}
        data-testid="ai-permission-mode-toggle"
      >
        {(['safe', 'power_user'] as const).map((mode) => {
          const selected = value === mode
          return (
            <ActionTooltip
              key={mode}
              copy={permissionModeTooltip(mode, t)}
              side="bottom"
              contentTestId="ai-permission-mode-tooltip"
            >
              <Button
                type="button"
                size="sm"
                variant="ghost"
                role="radio"
                aria-checked={selected}
                disabled={disabled}
                className={
                  selected
                    ? 'h-7 flex-1 border border-border bg-background text-foreground shadow-xs hover:bg-background'
                    : 'h-7 flex-1 text-muted-foreground hover:text-foreground'
                }
                onClick={() => onChange(mode)}
              >
                {aiAgentPermissionModeLabels(mode, locale).control}
              </Button>
            </ActionTooltip>
          )
        })}
      </div>
    </TooltipProvider>
  )
}

export const AiPanelContextBar = memo(function AiPanelContextBar({
  activeEntry,
  linkedCount,
  locale = 'en',
}: AiPanelContextBarProps) {
  const t = createTranslator(locale)

  return (
    <div
      className="flex shrink-0 items-center border-b border-border text-muted-foreground"
      style={{ padding: '6px 12px', gap: 6, fontSize: 11 }}
      data-testid="context-bar"
    >
      <Link size={12} className="shrink-0" />
      <span className="truncate" style={{ fontWeight: 500 }}>{activeEntry.title}</span>
      {linkedCount > 0 && (
        <span style={{ opacity: 0.6 }}>{t('ai.panel.linkedCount', { count: linkedCount })}</span>
      )}
    </div>
  )
})

export const AiPanelMessageHistory = memo(function AiPanelMessageHistory({
  agentLabel,
  agentReadiness,
  locale = 'en',
  messages,
  isActive,
  onForkMessage,
  onOpenNote,
  onNavigateWikilink,
  onRegenerateMessage,
  onScrollStateChange,
  hasContext,
}: AiPanelMessageHistoryProps) {
  const containerRef = useRef<HTMLDivElement>(null)
  const endRef = useRef<HTMLDivElement>(null)

  const updateScrollState = useCallback(() => {
    const element = containerRef.current
    onScrollStateChange?.((element?.scrollTop ?? 0) > 1)
  }, [onScrollStateChange])

  useEffect(() => {
    void isActive
    void messages
    endRef.current?.scrollIntoView({ behavior: 'smooth' })
    if (typeof window.requestAnimationFrame === 'function') window.requestAnimationFrame(updateScrollState)
    else updateScrollState()
  }, [messages, isActive, updateScrollState])

  return (
    <div ref={containerRef} className="flex-1 overflow-y-auto" style={{ padding: 12 }} onScroll={updateScrollState}>
      {messages.length === 0 && !isActive && (
        <AiPanelEmptyState
          agentLabel={agentLabel}
          agentReadiness={agentReadiness}
          locale={locale}
          hasContext={hasContext}
        />
      )}
      {messages.map((message, index) => (
        <AiMessage
          key={message.id ?? index}
          {...message}
          locale={locale}
          messageId={message.id}
          onFork={onForkMessage}
          onOpenNote={onOpenNote}
          onNavigateWikilink={onNavigateWikilink}
          onRegenerate={onRegenerateMessage}
        />
      ))}
      <div ref={endRef} />
    </div>
  )
})

export function AiPanelComposer({
  entries,
  agentLabel,
  agentReadiness,
  locale = 'en',
  input,
  inputRef,
  isActive,
  controls,
  onChange,
  onSend,
  onStop,
  onUnsupportedAiPaste,
}: AiPanelComposerProps) {
  const t = createTranslator(locale)
  const composerDisabled = isActive || agentReadiness !== 'ready'
  const canSend = !composerDisabled && input.trim().length > 0
  const placeholder = getComposerPlaceholder(agentLabel, agentReadiness, t)
  const hasControls = controls !== undefined && controls !== null
  const sendButton = isActive
    ? <ComposerStopButton label={t('ai.panel.stop')} onStop={onStop} />
    : (
        <ComposerSendButton
          canSend={canSend}
          entries={entries}
          input={input}
          label={t('ai.panel.send')}
          onSend={onSend}
        />
      )

  return (
    <div
      className="flex shrink-0 flex-col"
      style={{ padding: '6px 10px' }}
    >
      <div className={cn(
        hasControls ? 'rounded-xl border border-border bg-background px-2 py-1.5 shadow-xs' : 'flex items-end gap-2',
      )}>
        <div className={cn('min-w-0 flex-1', hasControls && 'w-full')}>
          <ComposerInput
            disabled={composerDisabled}
            entries={entries}
            hasControls={hasControls}
            input={input}
            inputRef={inputRef}
            onChange={onChange}
            onSend={onSend}
            onUnsupportedAiPaste={onUnsupportedAiPaste}
            placeholder={placeholder}
          />
        </div>
        <ComposerControlsRow hasControls={hasControls} sendButton={sendButton}>
          {controls}
        </ComposerControlsRow>
      </div>
    </div>
  )
}
