import { useMemo, type ReactNode } from 'react'
import { motion } from 'framer-motion'
import { cn } from '@/lib/utils'
import { Highlight } from 'prism-react-renderer'
import { CollapsibleCard } from '../basic/collapsible-card'
import { FileLine, LoaderLine } from '../basic/icons-inline'
import { getFileIconColorClass } from '../lib/file-icon-maps'

const ICON_CLASS = 'w-[var(--font-size-sm)] h-[var(--font-size-sm)] shrink-0'

/** Prism 主题：使用设计令牌，随 data-theme 生效 */
const codeBlockTheme = {
  plain: { color: 'var(--color-text)' },
  styles: [
    { types: ['comment', 'prolog', 'cdata'], style: { color: 'var(--color-text-tertiary)' } },
    { types: ['keyword', 'atrule'], style: { color: 'var(--color-blue)' } },
    { types: ['string', 'attr-value', 'inserted'], style: { color: 'var(--color-success)' } },
    { types: ['number', 'constant', 'boolean'], style: { color: 'var(--color-success)' } },
    { types: ['function', 'function-variable'], style: { color: 'var(--color-purple)' } },
    { types: ['punctuation', 'operator', 'deleted'], style: { color: 'var(--color-text-tertiary)' } },
    { types: ['property', 'tag', 'selector'], style: { color: 'var(--color-pink)' } },
    { types: ['regex', 'important', 'variable'], style: { color: 'var(--color-text)' } },
  ],
}

const LANG_EXT: Record<string, string> = {
  javascript: 'js', typescript: 'ts', jsx: 'jsx', tsx: 'tsx',
  python: 'py', java: 'java', go: 'go', rust: 'rs', html: 'html', css: 'css',
  json: 'json', yaml: 'yml', markdown: 'md', shell: 'sh', bash: 'sh',
}

export type CodeBlockDiffType = 'add' | 'remove'

export interface CodeBlockPartProps {
  language?: string
  code?: string
  filename?: string
  diffType?: CodeBlockDiffType | null
  diffLines?: number | null
  isGenerating?: boolean
  defaultExpanded?: boolean
  className?: string
  headerIcon?: ReactNode
  getFileIcon?: (fileType?: string, filename?: string) => ReactNode
}

function getDisplayFilename(filename?: string, language?: string): string {
  if (filename && filename.trim()) return filename
  const lang = (language ?? 'text').toLowerCase()
  const ext = LANG_EXT[lang] ?? 'txt'
  return `${lang}.${ext}`
}

export function CodeBlockPart({
  language = 'javascript',
  code = '',
  filename,
  diffType = null,
  diffLines = null,
  isGenerating = false,
  defaultExpanded = true,
  className,
  headerIcon,
  getFileIcon,
}: CodeBlockPartProps) {
  const displayName = useMemo(
    () => getDisplayFilename(filename, language),
    [filename, language]
  )

  const calculatedDiffLines = useMemo(() => {
    if (diffType && code) {
      const lines = code.split('\n')
      return lines.length
    }
    return diffLines ?? null
  }, [code, diffType, diffLines])

  const fileType = language?.toLowerCase()
  const defaultHeaderIcon = isGenerating ? (
    <motion.div
      animate={{ rotate: 360 }}
      transition={{ duration: 1, repeat: Infinity, ease: 'linear' }}
    >
      <LoaderLine className={cn(ICON_CLASS, 'text-text-secondary')} />
    </motion.div>
  ) : getFileIcon ? (
    getFileIcon(fileType, displayName)
  ) : (
    <span className={cn(getFileIconColorClass(fileType, displayName))}>
      <FileLine className={ICON_CLASS} />
    </span>
  )

  const headerRight =
    diffType && calculatedDiffLines != null ? (
      <span
        className={cn(
          'font-normal text-xs leading-xs',
          diffType === 'add' ? 'text-success' : 'text-error'
        )}
      >
        {diffType === 'add' ? '+' : '-'}{calculatedDiffLines}
      </span>
    ) : null

  const contentClass = cn(
    'overflow-x-auto text-left scrollbar-auto',
    diffType === 'add' &&
      'bg-success-bg border-l-[3px] border-l-[var(--color-success-border)] -ml-5 pl-5',
    diffType === 'remove' &&
      'bg-error-bg border-l-[3px] border-l-[var(--color-error-border)] -ml-5 pl-5'
  )

  const lang = (language ?? 'text').toLowerCase()

  return (
    <CollapsibleCard
      headerIcon={headerIcon ?? defaultHeaderIcon}
      headerTitle={<span className="font-normal">{displayName}</span>}
      headerRight={headerRight}
      defaultExpanded={defaultExpanded}
      contentPadding="var(--spacing-2) 0 var(--spacing-2) var(--spacing-5)"
      titleShimmer={isGenerating}
      className={className}
    >
      <div className={contentClass}>
        <Highlight theme={codeBlockTheme} code={code} language={lang}>
          {({ className: preClassName, style, tokens, getLineProps, getTokenProps }) => (
            <pre
              className={cn(preClassName, 'm-0 text-left bg-transparent font-mono text-xs font-normal leading-xs whitespace-pre')}
              style={style}
            >
              <code className="text-left block">
                {tokens.map((line, i) => (
                  <div key={i} {...getLineProps({ line })}>
                    {line.map((token, k) => (
                      <span key={k} {...getTokenProps({ token })} />
                    ))}
                  </div>
                ))}
              </code>
            </pre>
          )}
        </Highlight>
      </div>
    </CollapsibleCard>
  )
}

CodeBlockPart.displayName = 'CodeBlockPart'
export const CodeBlockCard = CodeBlockPart
export type CodeBlockCardProps = CodeBlockPartProps
