/*
  CommonJS runtime for resetting files and applying translations from Excel to source code.
  This script first resets files to their original state, then applies translations.
*/
const path = require('node:path')
const fs = require('node:fs')
const { execSync } = require('child_process')
const { Project, SyntaxKind, Node } = require('ts-morph')
const XLSX = require('xlsx')

const WORKDIR = process.cwd()
const TRANSLATES_FILE = path.join(WORKDIR, 'scripts', 'translates.xlsx')
const REPORT_FILE = path.join(WORKDIR, 'scripts', 'translation-report.json')
const CONFLICTS_FILE = path.join(WORKDIR, 'scripts', 'translation-conflicts.xlsx')

// 统计信息
const stats = {
  total: 0,
  success: 0,
  conflicts: 0,
  fileNotFound: 0,
  textNotFound: 0,
  multipleMatches: 0,
}

// 冲突列表
const conflicts = []

// 成功替换列表
const successfulReplacements = []

function resetFiles() {
  console.log('🔄 重置文件到原始状态...')
  try {
    // 使用 git 重置所有修改的文件
    execSync('git checkout -- .', { cwd: WORKDIR, stdio: 'inherit' })
    console.log('✅ 文件重置完成')
  } catch (error) {
    console.error('❌ 重置文件失败:', error.message)
    process.exit(1)
  }
}

function loadTranslations() {
  console.log('📖 读取翻译数据...')
  const wb = XLSX.readFile(TRANSLATES_FILE)
  const ws = wb.Sheets[wb.SheetNames[0]]
  const data = XLSX.utils.sheet_to_json(ws, { defval: '' })

  // 筛选出需要替换的条目
  let translations = data.filter(
    (row) => row.text && row.corrected_text && row.text !== row.corrected_text
  )

  // 去重：按 file + line + text 去重，保留第一个
  const seen = new Set()
  translations = translations.filter((row) => {
    const key = `${row.file}:${row.line}:${row.text}`
    if (seen.has(key)) {
      return false
    }
    seen.add(key)
    return true
  })

  console.log(`📊 找到 ${translations.length} 条需要替换的翻译（已去重）`)
  stats.total = translations.length

  return translations
}

function groupByFile(translations) {
  const groups = new Map()
  for (const translation of translations) {
    const filePath = path.join(WORKDIR, translation.file)
    if (!groups.has(filePath)) {
      groups.set(filePath, [])
    }
    groups.get(filePath).push(translation)
  }
  return groups
}

function findTextInFile(sourceFile, translation) {
  const { text, kind } = translation
  const matches = []

  sourceFile.forEachDescendant((node) => {
    // 根据 kind 类型进行不同的匹配
    if (kind === 'text') {
      // 查找 JSX 文本节点
      if (Node.isJsxText(node)) {
        const nodeText = node.getText().replace(/\s+/g, ' ').trim()
        if (nodeText === text) {
          matches.push({ node, type: 'jsx-text', line: node.getStartLineNumber() })
        }
      }
      // 查找 JSX 表达式中的字符串
      if (Node.isJsxExpression(node)) {
        const expr = node.getExpression()
        if (expr && (Node.isStringLiteral(expr) || Node.isNoSubstitutionTemplateLiteral(expr))) {
          const nodeText = expr.getLiteralText()
          if (nodeText === text) {
            matches.push({ node: expr, type: 'jsx-expression', line: node.getStartLineNumber() })
          }
        }
      }
    } else if (['placeholder', 'title', 'alt', 'label', 'aria'].includes(kind)) {
      // 查找 JSX 属性
      if (Node.isJsxAttribute(node)) {
        const name = node.getNameNode().getText().toLowerCase()
        const value = getStringFromInitializer(node)
        if (value === text) {
          matches.push({ node, type: 'jsx-attribute', line: node.getStartLineNumber() })
        }
      }
    } else if (['toast', 'dialog', 'error', 'validation'].includes(kind)) {
      // 查找函数调用中的字符串参数
      if (Node.isCallExpression(node)) {
        const args = node.getArguments()
        for (const arg of args) {
          if (Node.isStringLiteral(arg) || Node.isNoSubstitutionTemplateLiteral(arg)) {
            const nodeText = arg.getLiteralText()
            if (nodeText === text) {
              matches.push({ node: arg, type: 'function-arg', line: node.getStartLineNumber() })
            }
          }
        }
      }
    }
  })

  return matches
}

function getStringFromInitializer(attr) {
  const init = attr.getInitializer()
  if (!init) return undefined
  if (Node.isStringLiteral(init) || Node.isNoSubstitutionTemplateLiteral(init)) {
    return init.getLiteralText()
  }
  if (Node.isJsxExpression(init)) {
    const expr = init.getExpression()
    if (!expr) return undefined
    if (Node.isStringLiteral(expr) || Node.isNoSubstitutionTemplateLiteral(expr)) {
      return expr.getLiteralText()
    }
  }
  return undefined
}

function replaceText(node, newText, type) {
  try {
    if (type === 'jsx-text') {
      // JSX 文本节点需要特殊处理，保持空白字符
      const originalText = node.getText()
      const newTextWithWhitespace = originalText.replace(/\S+/g, newText)
      node.replaceWithText(newTextWithWhitespace)
    } else if (type === 'jsx-expression' || type === 'function-arg') {
      // 字符串字面量
      if (Node.isStringLiteral(node)) {
        node.replaceWithText(`"${newText}"`)
      } else if (Node.isNoSubstitutionTemplateLiteral(node)) {
        node.replaceWithText(`\`${newText}\``)
      }
    } else if (type === 'jsx-attribute') {
      // JSX 属性值
      const init = node.getInitializer()
      if (init) {
        if (Node.isStringLiteral(init)) {
          init.replaceWithText(`"${newText}"`)
        } else if (Node.isNoSubstitutionTemplateLiteral(init)) {
          init.replaceWithText(`\`${newText}\``)
        } else if (Node.isJsxExpression(init)) {
          const expr = init.getExpression()
          if (expr && (Node.isStringLiteral(expr) || Node.isNoSubstitutionTemplateLiteral(expr))) {
            if (Node.isStringLiteral(expr)) {
              expr.replaceWithText(`"${newText}"`)
            } else {
              expr.replaceWithText(`\`${newText}\``)
            }
          }
        }
      }
    }
    return true
  } catch (error) {
    console.error(`❌ 替换失败: ${error.message}`)
    return false
  }
}

function processFile(filePath, translations) {
  if (!fs.existsSync(filePath)) {
    console.log(`❌ 文件不存在: ${path.relative(WORKDIR, filePath)}`)
    translations.forEach((t) => {
      conflicts.push({
        ...t,
        conflictType: 'FILE_NOT_FOUND',
        conflictReason: '文件不存在',
      })
    })
    stats.fileNotFound += translations.length
    return
  }

  console.log(`📝 处理文件: ${path.relative(WORKDIR, filePath)}`)

  try {
    const project = new Project({
      tsConfigFilePath: path.join(WORKDIR, 'tsconfig.json'),
      skipAddingFilesFromTsConfig: true,
    })
    const sourceFile = project.addSourceFileAtPath(filePath)

    for (const translation of translations) {
      const { text, corrected_text, line, kind } = translation

      // 在文件中查找匹配的文本
      const matches = findTextInFile(sourceFile, translation)

      if (matches.length === 0) {
        conflicts.push({
          ...translation,
          conflictType: 'TEXT_NOT_FOUND_IN_FILE',
          conflictReason: '在文件中找不到匹配的文本',
        })
        stats.textNotFound++
        continue
      }

      if (matches.length > 1) {
        conflicts.push({
          ...translation,
          conflictType: 'MULTIPLE_MATCHES',
          conflictReason: `找到 ${matches.length} 个匹配项，需要人工确认`,
        })
        stats.multipleMatches++
        continue
      }

      // 执行替换
      const match = matches[0]
      const success = replaceText(match.node, corrected_text, match.type)

      if (success) {
        successfulReplacements.push({
          ...translation,
          actualLine: match.line,
          replacementType: match.type,
        })
        stats.success++
        console.log(`✅ 替换成功: "${text}" -> "${corrected_text}" (行 ${match.line})`)
      } else {
        conflicts.push({
          ...translation,
          conflictType: 'REPLACEMENT_FAILED',
          conflictReason: '替换操作失败',
        })
        stats.conflicts++
      }
    }

    // 保存修改后的文件
    sourceFile.saveSync()
  } catch (error) {
    console.error(`❌ 处理文件失败: ${filePath}`, error.message)
    translations.forEach((t) => {
      conflicts.push({
        ...t,
        conflictType: 'PARSE_ERROR',
        conflictReason: `文件解析失败: ${error.message}`,
      })
    })
    stats.conflicts += translations.length
  }
}

function generateReport() {
  console.log('\n📊 生成报告...')

  // 生成成功替换报告
  const report = {
    timestamp: new Date().toISOString(),
    stats,
    successfulReplacements,
    conflicts: conflicts.map((c) => ({
      file: c.file,
      line: c.line,
      text: c.text,
      corrected_text: c.corrected_text,
      conflictType: c.conflictType,
      conflictReason: c.conflictReason,
    })),
  }

  fs.writeFileSync(REPORT_FILE, JSON.stringify(report, null, 2))
  console.log(`📄 成功替换报告已保存: ${REPORT_FILE}`)

  // 生成冲突报告 Excel
  if (conflicts.length > 0) {
    const conflictRows = conflicts.map((c) => ({
      file: c.file,
      line: c.line,
      text: c.text,
      corrected_text: c.corrected_text,
      conflictType: c.conflictType,
      conflictReason: c.conflictReason,
      route: c.route,
      componentOrFn: c.componentOrFn,
      kind: c.kind,
      keyOrLocator: c.keyOrLocator,
    }))

    const ws = XLSX.utils.json_to_sheet(conflictRows)
    const wb = XLSX.utils.book_new()
    XLSX.utils.book_append_sheet(wb, ws, 'conflicts')
    XLSX.writeFile(wb, CONFLICTS_FILE)
    console.log(`📄 冲突报告已保存: ${CONFLICTS_FILE}`)
  }
}

function printSummary() {
  console.log('\n📈 处理完成！')
  console.log(`总翻译条目: ${stats.total}`)
  console.log(`✅ 成功替换: ${stats.success}`)
  console.log(`❌ 文件不存在: ${stats.fileNotFound}`)
  console.log(`❌ 文本未找到: ${stats.textNotFound}`)
  console.log(`❌ 多处匹配: ${stats.multipleMatches}`)
  console.log(`❌ 其他冲突: ${stats.conflicts}`)
  console.log(`\n成功率: ${((stats.success / stats.total) * 100).toFixed(1)}%`)
}

async function main() {
  console.log('🚀 开始重置并应用翻译...\n')

  try {
    // 1. 重置文件到原始状态
    resetFiles()

    // 2. 读取翻译数据
    const translations = loadTranslations()

    // 3. 按文件分组
    const fileGroups = groupByFile(translations)

    // 4. 处理每个文件
    for (const [filePath, fileTranslations] of fileGroups) {
      processFile(filePath, fileTranslations)
    }

    // 5. 生成报告
    generateReport()

    // 6. 打印总结
    printSummary()
  } catch (error) {
    console.error('❌ 执行失败:', error)
    process.exitCode = 1
  }
}

main()
