import type { TaskArtifact } from '../../types'

/**
 * 工具类型枚举
 */
export enum ToolType {
  SHELL_EXECUTE = 'shell_execute',
  SCRIPT_FILE = 'script_file',
  OTHER = 'other',
}

/**
 * 脚本文件扩展名
 */
const SCRIPT_EXTENSIONS = ['py', 'js', 'ts', 'sh', 'bash', 'zsh', 'fish', 'rb', 'php', 'go', 'rs', 'java', 'kt', 'swift']
const INLINE_PREVIEW_EXTENSIONS = [
  'md',
  'markdown',
  'txt',
  'html',
  'csv',
  'json',
  ...SCRIPT_EXTENSIONS,
]
const MIME_TYPE_ALIASES: Record<string, string> = {
  'text/markdown': 'md',
  'text/x-markdown': 'md',
  'application/markdown': 'md',
  'text/html': 'html',
  'application/pdf': 'pdf',
  'text/csv': 'csv',
  'application/csv': 'csv',
  'application/json': 'json',
  'text/plain': 'txt',
  'image/jpeg': 'jpg',
  'image/jpg': 'jpg',
  'image/png': 'png',
  'image/gif': 'gif',
  'image/webp': 'webp',
  'image/svg+xml': 'svg',
  'image/bmp': 'bmp',
  'application/vnd.ms-powerpoint': 'ppt',
  'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx',
  'application/vnd.ms-excel': 'xls',
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
  'application/msword': 'doc',
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
}
const TOOL_OUTPUT_FILE_TYPE_FIELDS = ['file_type', 'type', 'mime_type']
const TOOL_OUTPUT_FILE_NAME_FIELDS = ['file_name', 'name', 'title']
const TOOL_OUTPUT_PATH_FIELDS = ['path', 'file_path', 'file_url', 'url', 'download_url']
const TOOL_OUTPUT_CONTENT_FIELDS = ['content', 'text', 'body', 'source', 'code', 'file_content']

function toObject(data: unknown): Record<string, unknown> | null {
  if (!data) return null

  if (typeof data === 'string') {
    try {
      const parsed = JSON.parse(data)
      if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
        return parsed as Record<string, unknown>
      }
    } catch {
      return null
    }
  }

  if (typeof data === 'object' && !Array.isArray(data)) {
    return data as Record<string, unknown>
  }

  return null
}

function getCandidateObjects(data: Record<string, unknown>): Record<string, unknown>[] {
  const candidates = [data]

  for (const key of ['result', 'data', 'file']) {
    const nested = data[key]
    if (nested && typeof nested === 'object' && !Array.isArray(nested)) {
      candidates.push(nested as Record<string, unknown>)
    }
  }

  return candidates
}

function pickFirstString(
  objects: Record<string, unknown>[],
  fields: string[],
): string {
  for (const obj of objects) {
    for (const field of fields) {
      const value = obj[field]
      if (typeof value === 'string' && value.trim()) {
        return value.trim()
      }
    }
  }

  return ''
}

function getBaseName(path?: string): string {
  if (!path) return ''
  const cleanPath = path.split(/[?#]/)[0]
  const segments = cleanPath.split('/').filter(Boolean)
  return segments[segments.length - 1] || ''
}

function isInlinePreviewFileType(fileType: string): boolean {
  return INLINE_PREVIEW_EXTENSIONS.includes(fileType)
}

function isAbsoluteHttpUrl(value?: string): boolean {
  return !!value && /^https?:\/\//.test(value)
}

/**
 * 从路径中提取文件扩展名
 */
export function getFileExtension(path?: string): string {
  if (!path) return ''
  const baseName = getBaseName(path) || path
  const match = baseName.match(/\.([^.]+)$/)
  return match ? match[1].toLowerCase() : ''
}

/**
 * 统一文件类型，兼容扩展名与 MIME type
 */
export function normalizeArtifactFileType(
  fileType?: string,
  fileName?: string,
  path?: string,
): string {
  const normalizedFileType = (fileType || '')
    .trim()
    .toLowerCase()
    .split(';')[0]

  if (normalizedFileType) {
    if (MIME_TYPE_ALIASES[normalizedFileType]) {
      return MIME_TYPE_ALIASES[normalizedFileType]
    }

    if (normalizedFileType.includes('/')) {
      const subtype = normalizedFileType.split('/').pop() || ''

      if (subtype === 'svg+xml') return 'svg'
      if (subtype.includes('markdown')) return 'md'
      if (subtype.includes('presentationml.presentation')) return 'pptx'
      if (subtype.includes('ms-powerpoint')) return 'ppt'
      if (subtype.includes('spreadsheetml.sheet')) return 'xlsx'
      if (subtype.includes('ms-excel')) return 'xls'
      if (subtype.includes('wordprocessingml.document')) return 'docx'
      if (subtype.includes('msword')) return 'doc'

      return subtype
    }

    return normalizedFileType
  }

  return getFileExtension(fileName) || getFileExtension(path)
}

/**
 * 从 tool_input 中提取 file_path
 */
export function getFilePathFromInput(input: unknown): string {
  try {
    let obj: Record<string, unknown> | null = null
    if (typeof input === 'string') {
      obj = JSON.parse(input)
    } else if (input && typeof input === 'object') {
      obj = input as Record<string, unknown>
    }
    if (obj && typeof obj.file_path === 'string') {
      return obj.file_path
    }
  } catch {
    // ignore
  }
  return ''
}

/**
 * 判断普通文件是否是脚本类型（根据扩展名）
 */
export function isScriptLikeFile(artifact: TaskArtifact): boolean {
  const extFromPath = getFileExtension(artifact.path)
  const extFromName = getFileExtension(artifact.file_name)
  const extFromType = normalizeArtifactFileType(
    artifact.file_type,
    artifact.file_name,
    artifact.path,
  )

  const ext = extFromPath || extFromName || extFromType
  if (!ext) return false

  return SCRIPT_EXTENSIONS.includes(ext)
}

/**
 * 从 tool_output 中提取可直接预览的文件 artifact
 */
export function extractToolOutputArtifact(
  artifact: TaskArtifact,
): TaskArtifact | null {
  const rawOutput = toObject(artifact.tool_output)
  if (!rawOutput) return null

  const candidates = getCandidateObjects(rawOutput)
  const outputPath = pickFirstString(candidates, TOOL_OUTPUT_PATH_FIELDS)
  const outputName = pickFirstString(candidates, TOOL_OUTPUT_FILE_NAME_FIELDS)
  const outputType = pickFirstString(candidates, TOOL_OUTPUT_FILE_TYPE_FIELDS)
  const normalizedType = normalizeArtifactFileType(outputType, outputName, outputPath)
  const outputContent = pickFirstString(candidates, TOOL_OUTPUT_CONTENT_FIELDS)

  if (!normalizedType && !outputPath && !outputName) {
    return null
  }

  const canPreviewInline = !!outputContent && isInlinePreviewFileType(normalizedType)
  if (!outputPath && !canPreviewInline) {
    return null
  }

  const fallbackBaseName = artifact.tool_name || artifact.file_name || 'tool_output'
  const fallbackFileName = normalizedType
    ? `${fallbackBaseName}.${normalizedType}`
    : fallbackBaseName
  const fileName = outputName || getBaseName(outputPath) || fallbackFileName

  return {
    path: outputPath || '',
    file_name: fileName,
    file_type: normalizedType || getFileExtension(fileName),
    content: canPreviewInline ? outputContent : undefined,
    url: isAbsoluteHttpUrl(outputPath) ? outputPath : undefined,
    task_id: artifact.task_id,
  }
}

/**
 * 判断工具类型
 */
export function detectToolType(artifact: TaskArtifact): ToolType {
  const toolName = artifact.tool_name

  // 1. shell_execute 特殊处理
  if (toolName === 'shell_execute') {
    return ToolType.SHELL_EXECUTE
  }

  // 2. 检查文件扩展名
  const filePath = getFilePathFromInput(artifact.tool_input)
  const fileExt =
    getFileExtension(filePath) ||
    getFileExtension(artifact.path) ||
    getFileExtension(artifact.file_name) ||
    normalizeArtifactFileType(artifact.file_type, artifact.file_name, artifact.path)
  
  if (SCRIPT_EXTENSIONS.includes(fileExt)) {
    return ToolType.SCRIPT_FILE
  }

  // 3. 检查工具名称关键字
  if (toolName && (
    toolName.toLowerCase().includes('execute') ||
    toolName.toLowerCase().includes('shell') ||
    toolName.toLowerCase().includes('code') ||
    toolName.toLowerCase().includes('script') ||
    toolName.toLowerCase().includes('python') ||
    toolName.toLowerCase().includes('javascript') ||
    toolName.toLowerCase().includes('node') ||
    toolName.toLowerCase().includes('bash') ||
    toolName.toLowerCase().includes('cmd')
  )) {
    return ToolType.SCRIPT_FILE
  }

  return ToolType.OTHER
}

/**
 * 移除 ANSI 转义序列
 */
export function removeAnsiCodes(text: string): string {
  return text.replace(/\x1b\[[0-9;]*m/g, '')
}

/**
 * 从数据中提取字符串
 */
function extractFromObject(data: unknown, fields: string[]): string | null {
  let obj: Record<string, unknown> | null = null

  // 解析 JSON 字符串
  if (typeof data === 'string') {
    try {
      const parsed = JSON.parse(data)
      if (parsed && typeof parsed === 'object') {
        obj = parsed
      } else if (typeof parsed === 'string') {
        return parsed
      }
    } catch {
      return data
    }
  } else if (data && typeof data === 'object') {
    obj = data as Record<string, unknown>
  }

  // 从对象中提取字段
  if (obj) {
    for (const field of fields) {
      const value = obj[field]
      if (typeof value === 'string' && value) {
        return value
      }
    }
  }

  return null
}

/**
 * 提取 shell_execute 输出
 */
export function extractShellOutput(output: unknown): string {
  // 处理数组
  if (Array.isArray(output)) {
    if (output.length === 1 && typeof output[0] === 'string') {
      return removeAnsiCodes(output[0])
    }
    return removeAnsiCodes(output.filter(item => typeof item === 'string').join('\n'))
  }

  // 解析 JSON
  if (typeof output === 'string') {
    try {
      const parsed = JSON.parse(output)
      if (Array.isArray(parsed)) {
        if (parsed.length === 1 && typeof parsed[0] === 'string') {
          return removeAnsiCodes(parsed[0])
        }
        return removeAnsiCodes(parsed.filter(item => typeof item === 'string').join('\n'))
      }
    } catch {
      return removeAnsiCodes(output)
    }
  }

  // 从对象中提取
  const result = extractFromObject(output, ['output', 'result', 'stdout'])
  if (result) {
    return removeAnsiCodes(result)
  }

  return JSON.stringify(output, null, 2)
}

/**
 * 提取脚本代码
 */
export function extractScriptCode(input: unknown): string {
  const codeFields = [
    'file_content',
    'content',
    'code',
    'script',
    'command',
    'cmd',
    'source',
    'text',
    'body',
  ]

  const result = extractFromObject(input, codeFields)
  return result || JSON.stringify(input, null, 2)
}

/**
 * 获取显示标题
 */
export function getDisplayTitle(artifact: TaskArtifact): string {
  const filePath = getFilePathFromInput(artifact.tool_input)
  return filePath || artifact.file_name || artifact.tool_name || '未命名'
}
