'use client'

import { useState, useMemo } from 'react'
import { Check, Copy, FileText } from 'lucide-react'
import { cn } from '@/lib/utils'
import { t } from '@/lib/i18n'
import type { ContentBlock } from '@/lib/types'
import { AgentBlock, ParallelAgentIndicator, isAgentToolCall } from './agent-block'
import { TextBlock, ThinkingPanel, TurnStats, WaitingIndicator, ToolUseBlock } from './chat-blocks'
import { PermissionBlock, PermissionGroupBlock } from './chat-permissions'

type PermissionDecision = (requestId: string, decision: 'allow' | 'allow_session' | 'deny') => void

/* ── Copy AI reply (markdown) — shown on hover ── */

export function CopyMessageButton({ text }: { text: string }) {
  const [copied, setCopied] = useState(false)
  const handleCopy = async () => {
    try {
      await navigator.clipboard.writeText(text)
      setCopied(true)
      setTimeout(() => setCopied(false), 2000)
    } catch {
      /* clipboard unavailable */
    }
  }
  return (
    <button
      onClick={handleCopy}
      className="absolute top-0 right-0 flex items-center gap-1 px-2 py-1 rounded text-[11px] text-muted hover:text-primary bg-surface/80 backdrop-blur opacity-0 group-hover:opacity-100 focus-visible:opacity-100 transition-opacity"
      title={copied ? t('button.copied') : t('button.copy')}
    >
      {copied ? <Check size={12} className="text-green" /> : <Copy size={12} />}
    </button>
  )
}

/* ── User Message ── */

export function UserMessage({ blocks, fallbackContent }: { blocks: ContentBlock[]; fallbackContent: string }) {
  const textBlock = blocks.find(b => b.type === 'text')
  let text = textBlock?.type === 'text' ? textBlock.text : fallbackContent
  // Strip <template> blocks from display (sent to Agent but not shown to user)
  if (text && text.includes('<template')) {
    text = text.replace(/<template[\s\S]*?<\/template>/g, '').trim()
  }
  // Simplify /init display: just show "/init"
  if (text && /^\/init\s*[—–-]/.test(text)) {
    text = '/init'
  }
  const imageAttachments = blocks.filter(b => b.type === 'image_attachment') as Array<{ type: 'image_attachment'; url: string; name: string }>
  const fileAttachments = blocks.filter(b => b.type === 'file_attachment') as Array<{ type: 'file_attachment'; url: string; name: string; size: number; mimeType: string }>
  const hasAttachments = imageAttachments.length > 0 || fileAttachments.length > 0

  return (
    <div className="flex justify-end">
      <div className="max-w-[70%] px-4 py-2.5 rounded-2xl bg-indigo text-white">
        {text && <p className="text-[13px] leading-relaxed whitespace-pre-wrap">{text}</p>}

        {/* Image attachments: single = large, 2+ = 2x2 grid */}
        {imageAttachments.length > 0 && (
          <div className={cn(
            hasAttachments && text ? 'mt-2' : '',
            imageAttachments.length === 1 ? '' : 'grid grid-cols-2 gap-1',
          )}>
            {imageAttachments.slice(0, 4).map((img, idx) => (
              <div key={idx} className="relative">
                <img
                  src={img.url}
                  alt={img.name}
                  className={cn(
                    'rounded-lg object-cover cursor-pointer hover:opacity-90 transition-opacity',
                    imageAttachments.length === 1 ? 'max-w-[300px] max-h-[300px]' : 'w-full h-[120px]',
                  )}
                  onClick={() => window.open(img.url, '_blank')}
                />
                {/* "+N" badge on the 4th image if more than 4 */}
                {idx === 3 && imageAttachments.length > 4 && (
                  <div className="absolute inset-0 rounded-lg bg-black/50 flex items-center justify-center">
                    <span className="text-white text-[16px] font-semibold">+{imageAttachments.length - 4}</span>
                  </div>
                )}
              </div>
            ))}
          </div>
        )}

        {/* File attachments: vertical list of cards */}
        {fileAttachments.length > 0 && (
          <div className={cn('space-y-1', (text || imageAttachments.length > 0) ? 'mt-2' : '')}>
            {fileAttachments.map((file, idx) => {
              const sizeStr = file.size > 0
                ? file.size > 1024 * 1024 ? `${(file.size / 1024 / 1024).toFixed(1)} MB`
                : file.size > 1024 ? `${(file.size / 1024).toFixed(0)} KB`
                : `${file.size} B`
                : ''
              return (
                <div key={idx} className="flex items-center gap-2 px-2.5 py-1.5 rounded-lg bg-white/10 text-white/90">
                  <FileText size={16} className="text-white/80 shrink-0" />
                  <span className="text-[12px] truncate max-w-[200px]">{file.name}</span>
                  {sizeStr && <span className="text-[10px] text-white/50 shrink-0">{sizeStr}</span>}
                </div>
              )
            })}
          </div>
        )}
      </div>
    </div>
  )
}

/* ── Assistant Message ── */

/** Indexed lookups for a tool_use block's related result/progress/agent content. */
type ToolRelation = {
  result?: Extract<ContentBlock, { type: 'tool_result' }>
  rawResult?: Extract<ContentBlock, { type: 'tool_raw_result' }>
  progress?: Extract<ContentBlock, { type: 'tool_progress' }>
  agentContent?: Extract<ContentBlock, { type: 'agent_content' }>
}

export function AssistantMessage({ blocks, streaming, isThinking, thinkingMode, onPermissionDecision, elapsedSeconds, inputTokens, outputTokens }: {
  blocks: ContentBlock[]
  streaming: boolean
  isThinking?: boolean
  thinkingMode?: string
  onPermissionDecision?: PermissionDecision
  elapsedSeconds?: number
  inputTokens?: number
  outputTokens?: number
}) {
  const nonThinkingBlocks = blocks.filter(b => b.type !== 'thinking')
  const thinkingBlocks = blocks.filter(b => b.type === 'thinking')
  const hasContent = nonThinkingBlocks.length > 0
  // Show "Thinking..." label based on thinking mode:
  //   max  → immediately (we know it will think)
  //   auto → only after SDK sends thinking_start (isThinking)
  //   off  → never
  const showThinkingLabel = streaming && !hasContent && (
    thinkingMode === 'max' || (thinkingMode === 'auto' && isThinking) ||
    // Legacy value support
    thinkingMode === 'enabled' || (thinkingMode === 'adaptive' && isThinking)
  )

  // Markdown source of the reply = concatenated text blocks (excludes tool calls,
  // thinking, permissions). Used by the copy button — copies raw markdown.
  const markdownText = blocks
    .filter(b => b.type === 'text')
    .map(b => (b.type === 'text' ? b.text : ''))
    .join('\n\n')

  // Pre-index blocks by tool_use_id so each tool card looks up its result /
  // raw result / progress / agent-content in O(1) instead of a linear scan per
  // block (this is the streaming hot path — it re-renders on every token).
  const { toolRelations, completedToolUseIds, runningAgents } = useMemo(() => {
    const toolRelations = new Map<string, ToolRelation>()
    const completedToolUseIds = new Set<string>()
    const entryOf = (id: string): ToolRelation => {
      let e = toolRelations.get(id)
      if (!e) {
        e = {}
        toolRelations.set(id, e)
      }
      return e
    }
    for (const b of blocks) {
      if (b.type === 'tool_result') {
        completedToolUseIds.add(b.tool_use_id)
        entryOf(b.tool_use_id).result = b
      } else if (b.type === 'tool_raw_result') {
        entryOf(b.tool_use_id).rawResult = b
      } else if (b.type === 'tool_progress') {
        entryOf(b.tool_use_id).progress = b
      } else if (b.type === 'agent_content') {
        entryOf(b.parent_tool_use_id).agentContent = b
      }
    }
    // Count agent tool calls with no result yet (matches completedToolUseIds
    // regardless of block order — equivalent to the original blocks.some scan).
    const runningAgents = blocks.filter(
      (b) => b.type === 'tool_use' && isAgentToolCall(b.name) && !completedToolUseIds.has(b.id),
    ).length
    return { toolRelations, completedToolUseIds, runningAgents }
  }, [blocks])

  return (
    <div className="group relative">
      {markdownText && !streaming && <CopyMessageButton text={markdownText} />}
      <div className="space-y-3">
        {!hasContent && streaming && <WaitingIndicator label={showThinkingLabel ? 'Thinking...' : undefined} />}
        {/* Collapsible thinking panel */}
        {thinkingBlocks.length > 0 && (
          <ThinkingPanel text={thinkingBlocks.map(b => b.type === 'thinking' ? b.text : '').join('')} streaming={streaming && !hasContent} />
        )}
        {/* Parallel agent indicator: count agent tool_use blocks that haven't received results yet */}
        <ParallelAgentIndicator count={runningAgents} />
        {(() => {
          // Group permission requests by toolName. Both pending and resolved
          // same-tool requests are merged into a single card to reduce visual clutter.
          type PermBlock = Extract<ContentBlock, { type: 'permission_request' }>
          const permByTool = new Map<string, Array<{ idx: number; block: PermBlock }>>()
          blocks.forEach((block, idx) => {
            if (block.type === 'permission_request') {
              const key = block.toolName
              if (!permByTool.has(key)) permByTool.set(key, [])
              permByTool.get(key)!.push({ idx, block })
            }
          })
          // Groups with 2+ entries render at the first occurrence; others are skipped
          const groupRenderedAt = new Map<string, number>()
          const groupedIndices = new Set<number>()
          for (const [toolName, entries] of permByTool) {
            if (entries.length > 1) {
              groupRenderedAt.set(toolName, entries[0].idx)
              for (const e of entries) groupedIndices.add(e.idx)
            }
          }

          return blocks.map((block, i) => {
            switch (block.type) {
              case 'text':
                return <TextBlock key={`text-${i}`} text={block.text} isLast={i === blocks.length - 1 && streaming} />
              case 'tool_use': {
                // Hide tool card while its permission is pending or was denied/timed out.
                // Tools should only render AFTER the user grants permission.
                const perm = blocks.find(b =>
                  b.type === 'permission_request' &&
                  (b.toolUseId === block.id || (!b.toolUseId && b.toolName === block.name))
                )
                if (perm && perm.type === 'permission_request' && perm.status !== 'allowed' && perm.status !== 'allowed_session') {
                  return null
                }

                const rel = toolRelations.get(block.id)
                const result = rel?.result
                const rawResult = rel?.rawResult
                const progress = rel?.progress
                const hasResult = !!result
                const isResultError = result?.type === 'tool_result' && result.is_error
                const resultContent = result?.type === 'tool_result' ? result.content : undefined
                const rawContent = rawResult?.type === 'tool_raw_result' ? rawResult.raw_content : undefined
                const toolElapsed = progress?.type === 'tool_progress' ? progress.elapsed_time_seconds : 0

                // Route agent/sub-agent calls to dedicated AgentBlock
                if (isAgentToolCall(block.name)) {
                  const agentInput = block.input as { description?: string; prompt?: string; subagent_type?: string }
                  const agentName = agentInput.subagent_type || agentInput.description || 'agent'
                  const agentTask = agentInput.prompt || agentInput.description || ''
                  // Find structured sub-blocks from agent_content events
                  const agentContentBlock = rel?.agentContent
                  const agentSubBlocks = agentContentBlock?.type === 'agent_content'
                    ? (agentContentBlock as { blocks: import('@/lib/types').AgentSubBlock[] }).blocks
                    : undefined
                  return (
                    <AgentBlock
                      key={block.id}
                      toolUseId={block.id}
                      agentName={agentName}
                      task={agentTask}
                      hasResult={hasResult}
                      isResultError={isResultError}
                      resultContent={resultContent}
                      rawContent={rawContent}
                      elapsedSeconds={toolElapsed}
                      streaming={streaming}
                      allBlocks={blocks}
                      agentSubBlocks={agentSubBlocks}
                    />
                  )
                }

                return <ToolUseBlock key={block.id} name={block.name} input={block.input} hasResult={hasResult} isResultError={isResultError} resultContent={resultContent} rawContent={rawContent} streaming={streaming} />
              }
              case 'tool_result':
              case 'tool_raw_result':
              case 'tool_progress':
              case 'agent_content':
                return null // Results/progress/agent-content are shown inside ToolUseBlock/AgentBlock
              case 'permission_request': {
                if (groupedIndices.has(i)) {
                  if (groupRenderedAt.get(block.toolName) === i) {
                    const group = permByTool.get(block.toolName)!
                    return <PermissionGroupBlock key={`perm-group-${block.toolName}`} requests={group.map(e => e.block)} onDecision={onPermissionDecision} />
                  }
                  return null // Skip — handled by the group
                }
                return <PermissionBlock key={block.requestId} requestId={block.requestId} toolName={block.toolName} toolInput={block.toolInput} status={block.status} toolFailed={block.toolFailed} onDecision={onPermissionDecision} />
              }
              case 'image_attachment': {
                const img = block as { url: string; name: string }
                return (
                  <div key={`img-${i}`} className="mt-2">
                    <img
                      src={img.url}
                      alt={img.name}
                      className="rounded-lg max-w-[300px] max-h-[300px] object-cover cursor-pointer hover:opacity-90 transition-opacity"
                      onClick={() => window.open(img.url, '_blank')}
                    />
                  </div>
                )
              }
              case 'file_attachment': {
                const file = block as { url: string; name: string; size: number; mimeType: string }
                const sizeStr = file.size > 1024 * 1024 ? `${(file.size / 1024 / 1024).toFixed(1)} MB` : file.size > 1024 ? `${(file.size / 1024).toFixed(0)} KB` : `${file.size} B`
                return (
                  <a key={`file-${i}`} href={file.url} target="_blank" rel="noreferrer" className="mt-2 flex items-center gap-2 px-3 py-2 rounded-lg bg-elevated border border-subtle hover:bg-surface-hover transition-colors max-w-fit">
                    <FileText size={16} className="text-tertiary shrink-0" />
                    <span className="text-[13px] text-primary truncate max-w-[250px]">{file.name}</span>
                    <span className="text-[11px] text-muted shrink-0">{sizeStr}</span>
                  </a>
                )
              }
              default:
                return null
            }
          })
        })()}
        {(elapsedSeconds != null && elapsedSeconds > 0) && (
          <TurnStats elapsedSeconds={elapsedSeconds} inputTokens={inputTokens} outputTokens={outputTokens} streaming={streaming} />
        )}
      </div>
    </div>
  )
}
