import { useState, type ReactNode } from 'react'
import { cn } from '@/lib/utils'
import { CollapsibleCard } from '../basic/collapsible-card'
import { Button } from '../basic/button'
import { RequestChangesLine, CheckLine, CloseLine } from '../basic/icons-inline'

const ICON_CLASS = 'w-[var(--font-size-sm)] h-[var(--font-size-sm)] shrink-0'
/** Seti 图标：固定 16px，与 QodeChatPanel 的 w-4 h-4 一致 */
const SETI_ICON_CLASS =
  "font-['Seti'] shrink-0 inline-flex items-center justify-center w-4 h-4 text-[16px] leading-[16px]"

// 与 QodeChatPanel FileReviewPart.jsx 内联映射完全一致（qoder-seti.woff）
const SETI_CHAR_MAP: Record<string, string> = {
  javascript: '\ue054',
  typescript: '\ue099',
  react: '\ue07d',
  json: '\ue059',
  html: '\ue048',
  css: '\ue01d',
  python: '\ue07b',
  java: '\ue050',
  go: '\ue039',
  rust: '\ue082',
  php: '\ue070',
  ruby: '\ue081',
  vue: '\ue09d',
  svelte: '\ue090',
  markdown: '\ue060',
  yaml: '\ue0a7',
  xml: '\ue0a5',
  shell: '\ue089',
  sass: '\ue084',
  settings: '\ue019',
  default: '\ue023',
}
const SETI_COLOR_MAP: Record<string, string> = {
  javascript: 'var(--color-yellow)',
  typescript: 'var(--color-blue)',
  react: 'var(--color-blue)',
  json: 'var(--color-yellow)',
  html: 'var(--color-blue)',
  css: 'var(--color-blue)',
  python: 'var(--color-blue)',
  java: 'var(--color-error)',
  go: 'var(--color-blue)',
  rust: 'var(--color-lavender)',
  php: 'var(--color-purple)',
  ruby: 'var(--color-error)',
  vue: 'var(--color-success)',
  svelte: 'var(--color-error)',
  markdown: 'var(--color-blue)',
  yaml: 'var(--color-purple)',
  xml: 'var(--color-orange)',
  shell: 'var(--color-success)',
  sass: 'var(--color-error)',
  settings: 'var(--color-lavender)',
  default: 'var(--color-lavender)',
}
const FILE_TYPE_MAP: Record<string, string> = {
  js: 'javascript',
  jsx: 'react',
  ts: 'typescript',
  tsx: 'typescript',
  json: 'json',
  html: 'html',
  css: 'css',
  scss: 'sass',
  sass: 'sass',
  less: 'css',
  py: 'python',
  java: 'java',
  go: 'go',
  rs: 'rust',
  php: 'php',
  rb: 'ruby',
  vue: 'vue',
  svelte: 'svelte',
  md: 'markdown',
  yml: 'yaml',
  yaml: 'yaml',
  xml: 'xml',
  sh: 'shell',
  bash: 'shell',
  zsh: 'shell',
  config: 'settings',
  conf: 'settings',
}

function getSetiIconType(fileType?: string, filename?: string): string {
  let iconType: string | null = null
  if (filename && typeof filename === 'string' && filename.trim()) {
    const lastDotIndex = filename.lastIndexOf('.')
    if (lastDotIndex > 0 && lastDotIndex < filename.length - 1) {
      const ext = filename.substring(lastDotIndex + 1).toLowerCase().trim()
      if (ext && FILE_TYPE_MAP[ext]) iconType = FILE_TYPE_MAP[ext]
    }
  }
  if (!iconType && fileType && typeof fileType === 'string' && fileType.trim()) {
    const lowerFileType = fileType.toLowerCase().trim()
    if (FILE_TYPE_MAP[lowerFileType]) iconType = FILE_TYPE_MAP[lowerFileType]
    else if (SETI_CHAR_MAP[lowerFileType]) iconType = lowerFileType
  }
  return iconType || 'default'
}

function getSetiIcon(fileType?: string, filename?: string): string {
  const iconType = getSetiIconType(fileType, filename)
  return SETI_CHAR_MAP[iconType] ?? SETI_CHAR_MAP.default
}

function getSetiIconColor(fileType?: string, filename?: string): string {
  const iconType = getSetiIconType(fileType, filename)
  return SETI_COLOR_MAP[iconType] ?? SETI_COLOR_MAP.default
}

export interface FileReviewFile {
  filename: string
  fileType?: string
  additions?: number
  deletions?: number
}

export interface FileReviewPartProps {
  files?: FileReviewFile[]
  defaultExpanded?: boolean
  className?: string
  /** 卡片标题区图标，未传则用内联 SVG */
  headerIcon?: ReactNode
  /** 接受按钮图标，未传则用内联 SVG */
  acceptIcon?: ReactNode
  /** 拒绝按钮图标，未传则用内联 SVG */
  rejectIcon?: ReactNode
  /** 按文件类型/文件名渲染图标；未传则用 Seti 字体字符（需加载 qoder-seti.woff） */
  getFileIcon?: (fileType?: string, filename?: string) => ReactNode
}

export function FileReviewPart({
  files = [],
  defaultExpanded = true,
  className,
  headerIcon,
  acceptIcon,
  rejectIcon,
  getFileIcon,
}: FileReviewPartProps) {
  const [hoveredIndex, setHoveredIndex] = useState<number | null>(null)
  const defaultHeaderIcon = <RequestChangesLine className={cn(ICON_CLASS, 'text-text-secondary')} />
  const actionIconSize = 'w-[var(--font-size-sm)] h-[var(--font-size-sm)]'
  const defaultAcceptIcon = <CheckLine className={actionIconSize} />
  const defaultRejectIcon = <CloseLine className={actionIconSize} />
  const actionBtnClass =
    'flex items-center justify-center shrink-0 rounded cursor-pointer transition-colors duration-200 text-text-secondary hover:text-text focus:outline-none focus-visible:ring-2 focus-visible:ring-primary'

  return (
    <CollapsibleCard
      headerIcon={headerIcon ?? defaultHeaderIcon}
      headerTitle={
        <span className="font-normal">
          {files.length} {files.length === 1 ? 'File' : 'Files'}
        </span>
      }
      headerRight={
        <div className="flex items-center gap-1.5">
          <Button variant="ghost" size="sm" onClick={(e) => e.stopPropagation()}>
            Undo All
          </Button>
          <Button variant="ghost" size="sm" onClick={(e) => e.stopPropagation()}>
            Keep All
          </Button>
          <Button variant="secondary" size="sm" onClick={(e) => e.stopPropagation()}>
            Review
          </Button>
        </div>
      }
      defaultExpanded={defaultExpanded}
      contentPadding="var(--spacing-1\.5) var(--spacing-1) var(--spacing-1\.5)"
      className={className}
    >
      <div className="flex flex-col gap-0.5">
        {files.map((file, index) => {
          const isHovered = hoveredIndex === index
          const add = file.additions != null && Number.isFinite(file.additions) ? file.additions : null
          const del = file.deletions != null && Number.isFinite(file.deletions) ? file.deletions : null

          return (
            <div
              key={index}
              className={cn(
                'flex items-center gap-1 px-1 py-1 rounded-sm cursor-pointer transition-colors duration-200 relative h-6',
                isHovered ? 'bg-fill-secondary' : 'bg-transparent'
              )}
              onMouseEnter={() => setHoveredIndex(index)}
              onMouseLeave={() => setHoveredIndex(null)}
            >
              {getFileIcon ? (
                <span className={cn('shrink-0', ICON_CLASS)}>{getFileIcon(file.fileType, file.filename)}</span>
              ) : (
                <span
                  className={cn('shrink-0', SETI_ICON_CLASS)}
                  style={{ color: getSetiIconColor(file.fileType, file.filename) }}
                  aria-hidden
                >
                  {getSetiIcon(file.fileType, file.filename)}
                </span>
              )}
              <span
                className={cn(
                  'flex-1 text-xs font-medium truncate pr-12',
                  isHovered ? 'text-text' : 'text-text-tertiary'
                )}
              >
                {file.filename}
              </span>
              {/* 默认展示 diff 统计，hover 时淡出 */}
              <div
                className={cn(
                  'absolute right-1 flex items-center gap-0.5 text-xs font-medium shrink-0 transition-opacity duration-200',
                  isHovered ? 'opacity-0 pointer-events-none' : 'opacity-100'
                )}
              >
                {add != null && <span className="text-success">+{add}</span>}
                {del != null && <span className="text-error">-{del}</span>}
              </div>
              {/* Hover 时显示的对号/错号按钮，始终挂载用 opacity 控制显隐；用原生 button 保证图标可见 */}
              <div
                className={cn(
                  'flex items-center gap-0.5 shrink-0 absolute right-1 transition-opacity duration-200',
                  isHovered ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'
                )}
                onClick={(e) => e.stopPropagation()}
              >
                <button
                  type="button"
                  className={cn(actionBtnClass, 'h-6 min-w-6 [&_svg]:w-[var(--font-size-sm)] [&_svg]:h-[var(--font-size-sm)]')}
                  title="Reject"
                  aria-label="Reject"
                  onClick={(e) => e.stopPropagation()}
                >
                  {rejectIcon ?? defaultRejectIcon}
                </button>
                <button
                  type="button"
                  className={cn(actionBtnClass, 'h-6 min-w-6 [&_svg]:w-[var(--font-size-sm)] [&_svg]:h-[var(--font-size-sm)]')}
                  title="Accept"
                  aria-label="Accept"
                  onClick={(e) => e.stopPropagation()}
                >
                  {acceptIcon ?? defaultAcceptIcon}
                </button>
              </div>
            </div>
          )
        })}
      </div>
    </CollapsibleCard>
  )
}

FileReviewPart.displayName = 'FileReviewPart'
export const FileReviewCard = FileReviewPart
export type FileReviewCardProps = FileReviewPartProps
