#!/usr/bin/env node

/**
 * 统一视频生产流程编排器
 *
 * 串联: 生图 → 上传 → 生视频 → TTS → 成片
 * manifest.json 是唯一数据源，支持断点续跑
 *
 * 模块结构:
 *   pipeline.js              ← CLI 入口 + 编排逻辑（本文件）
 *   lib/pipeline-utils.js    ← 共享工具函数 & 路径常量
 *   lib/phase-*.js           ← 各阶段处理器
 *   lib/cmd-*.js             ← 子命令实现
 *
 * 用法:
 *   node scripts/pipeline.js run --manifest ./output/batch/manifest.json --account military --resume
 *   node scripts/pipeline.js run --manifest ./output/batch/manifest.json --phase upload,videos
 *   node scripts/pipeline.js status --manifest ./output/batch/manifest.json
 */

const { loadManifest, saveManifest, loadAccountConfig, log } = require('./lib/pipeline-utils')
const { phaseImages } = require('./lib/phase-images')
const { phaseUpload } = require('./lib/phase-upload')
const { phaseVideos } = require('./lib/phase-videos')
const { phaseTts } = require('./lib/phase-tts')
const { phaseAssemble } = require('./lib/phase-assemble')
const { initManifest } = require('./lib/cmd-init')
const { validateManifest, validateAccount } = require('./lib/cmd-validate')
const { showStatus } = require('./lib/cmd-status')
const { confirmManifest } = require('./lib/cmd-confirm')
const { createAccount } = require('./lib/cmd-create-account')

// ============================================================================
// 阶段注册表
// ============================================================================

const ALL_PHASES = ['tts', 'images', 'upload', 'videos', 'assemble']

const PHASE_HANDLERS = {
  tts: phaseTts,
  images: phaseImages,
  upload: phaseUpload,
  videos: phaseVideos,
  assemble: phaseAssemble,
}

// ============================================================================
// Pipeline 编排
// ============================================================================

async function runPipeline(manifestPath, options) {
  const manifest = loadManifest(manifestPath)

  // 加载账号配置
  const accountId = manifest.account || options.account
  let accountConfig = {}
  if (accountId) {
    accountConfig = loadAccountConfig(accountId)
    log('pipeline', `账号: ${accountConfig.name || accountId}`)
  }

  const phases = options.phases || ALL_PHASES

  if (!manifest.pipeline) {
    manifest.pipeline = { phases: {} }
  }

  // --retry-failed: 重置失败 item 状态
  if (options.retryFailed) {
    applyRetryFailed(manifest, phases)
  }

  log('pipeline', `阶段: ${phases.join(' → ')}`)

  for (const phase of phases) {
    const handler = PHASE_HANDLERS[phase]
    if (!handler) { log('pipeline', `未知阶段: ${phase}`); continue }

    if (options.resume && manifest.pipeline.phases[phase] === 'done') {
      log(phase, '已完成，跳过 (--resume)')
      continue
    }

    manifest.pipeline.phases[phase] = 'running'
    saveManifest(manifestPath, manifest)

    try {
      await handler(manifest, manifestPath, { ...options, accountConfig })

      const failedCount = manifest.items.filter(it => it.status === 'failed').length
      if (failedCount > 0) {
        manifest.pipeline.phases[phase] = 'partial'
        log(phase, `完成 (${failedCount} 个失败)`)
      } else {
        manifest.pipeline.phases[phase] = 'done'
        log(phase, '完成')
      }
    } catch (err) {
      manifest.pipeline.phases[phase] = 'failed'
      log(phase, `阶段失败: ${err.message}`)
      saveManifest(manifestPath, manifest)
      throw err
    }
    saveManifest(manifestPath, manifest)
  }

  log('pipeline', '全部完成')
}

function applyRetryFailed(manifest, phases) {
  let resetCount = 0
  for (const item of manifest.items) {
    if (item.status === 'failed' || item.status === 'partial') {
      if (item.url && item.videoPrompt && !item.video) {
        // 图片已上传但视频未生成 → 直接重试视频阶段
        item.status = 'done'
        item.error = ''
        resetCount++
      } else if (!item.url && item.imagePrompt) {
        // 图片未上传 → 重试图片阶段
        // 如果首帧已存在但 lastFrame 失败，只重置 lastFrame 相关
        if (item.file && manifest.mode === 'framePair' && !item.lastFrame) {
          item.status = 'done'  // 保留首帧，只补 lastFrame
          item.error = ''
          resetCount++
        } else {
          item.status = 'pending'
          item.error = ''
          delete item.file  // 清除旧文件引用，避免重复
          resetCount++
        }
      }
    }
  }
  if (phases.includes('videos')) {
    if (manifest.items.some(it => it.status === 'done' && it.url && it.videoPrompt && !it.video)) {
      manifest.pipeline.phases.videos = 'pending'
    }
  }
  if (phases.includes('images')) {
    if (manifest.items.some(it => (!it.status || it.status === 'pending') || (it.status === 'done' && manifest.mode === 'framePair' && !it.lastFrame))) {
      manifest.pipeline.phases.images = 'pending'
    }
  }
  if (phases.includes('upload')) manifest.pipeline.phases.upload = 'pending'
  if (phases.includes('tts')) manifest.pipeline.phases.tts = 'pending'
  if (resetCount > 0) log('pipeline', `重置 ${resetCount} 个失败 item (--retry-failed)`)
}

// ============================================================================
// CLI 参数解析
// ============================================================================

function parseArgs(argv) {
  const args = {}
  for (let i = 0; i < argv.length; i++) {
    if (argv[i] === '--manifest' && argv[i + 1]) args.manifest = argv[++i]
    else if (argv[i] === '--account' && argv[i + 1]) args.account = argv[++i]
    else if (argv[i] === '--phase' && argv[i + 1]) args.phases = argv[++i].split(',')
    else if (argv[i] === '--resume') args.resume = true
    else if (argv[i] === '--retry-failed') args.retryFailed = true
    else if (argv[i] === '--mode' && argv[i + 1]) args.mode = argv[++i]
    else if (argv[i] === '--items' && argv[i + 1]) args.items = argv[++i]
    else if (argv[i] === '--items-file' && argv[i + 1]) args.itemsFile = argv[++i]
    else if (argv[i] === '--id' && argv[i + 1]) args.id = argv[++i]
    else if (argv[i] === '--name' && argv[i + 1]) args.name = argv[++i]
    else if (argv[i] === '--desc' && argv[i + 1]) args.desc = argv[++i]
    else if (argv[i] === '--format' && argv[i + 1]) args.format = argv[++i]
    else if (argv[i] === '--image-model' && argv[i + 1]) args.imageModel = argv[++i]
    else if (argv[i] === '--video-model' && argv[i + 1]) args.videoModel = argv[++i]
    else if (argv[i] === '--references' && argv[i + 1]) args.references = argv[++i]
    else if (argv[i] === '--all') args.all = true
    else if (!args.command) args.command = argv[i]
  }
  return args
}

// ============================================================================
// CLI 入口
// ============================================================================

async function main() {
  const args = parseArgs(process.argv.slice(2))
  const command = args.command

  if (command === 'init') {
    initManifest(args)
    return
  }

  if (command === 'validate') {
    if (!args.manifest) { console.error('用法: pipeline.js validate --manifest <path>'); process.exit(1) }
    validateManifest(args.manifest)
    return
  }

  if (command === 'confirm') {
    confirmManifest(args)
    return
  }

  if (command === 'status') {
    if (!args.manifest) { console.error('用法: pipeline.js status --manifest <path>'); process.exit(1) }
    showStatus(args.manifest)
    return
  }

  if (command === 'run') {
    if (!args.manifest) { console.error('用法: pipeline.js run --manifest <path> [--account id] [--phase p1,p2] [--resume] [--retry-failed]'); process.exit(1) }
    await runPipeline(args.manifest, args)
    return
  }

  if (command === 'create-account') {
    await createAccount(args)
    return
  }

  if (command === 'validate-account') {
    if (!args.account) { console.error('用法: pipeline.js validate-account --account <id>'); process.exit(1) }
    validateAccount(args.account)
    return
  }

  console.log('用法:')
  console.log('  pipeline.js create-account --id <id> --name <名称> [--desc ...] [--references file1,file2]')
  console.log('  pipeline.js validate-account --account <id>')
  console.log('  pipeline.js init --account <id> --mode <single|framePair> --items <JSON> [--items-file <path>] [--image-model gemini|gpt-image|mj] [--video-model veo3-fast|grok|kling] [--format 9:16]')
  console.log('  pipeline.js validate --manifest <path>')
  console.log('  pipeline.js confirm --manifest <path> --all')
  console.log('  pipeline.js confirm --manifest <path> --items 1,3,5')
  console.log('  pipeline.js run --manifest <path> --phase tts,images,upload,videos,assemble')
  console.log('  pipeline.js run --manifest <path> --resume')
  console.log('  pipeline.js status --manifest <path>')
  console.log('')
  console.log('Manifest 路径约定: output/{account}_{date}_{NNN}/manifest.json（同天自增序号）')
  console.log('阶段: tts → images → upload → videos → assemble（TTS提前）')
}

if (require.main === module) {
  main().catch(err => {
    console.error(`\n错误: ${err.message}`)
    process.exit(1)
  })
}

module.exports = { runPipeline, showStatus, initManifest, validateManifest, createAccount, validateAccount }
