#!/usr/bin/env node

/**
 * OSS 文件上传工具
 *
 * 上传图片/视频到阿里云 OSS，返回签名 URL。
 * 支持单文件和批量上传。
 *
 * 用法:
 *   node oss-upload.js ./image.png
 *   node oss-upload.js ./video.mp4 --dir videos/
 *   node oss-upload.js batch ./manifest.json
 */

const OSS = require('ali-oss')
const path = require('path')
const fs = require('fs')

// ============================================================================
// 配置
// ============================================================================

function getConfig() {
  const configPath = path.join(__dirname, '..', '..', 'config.json')
  const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
  if (!config.ossRegion || !config.ossAccessKeyId || !config.ossAccessKeySecret || !config.ossBucket) {
    console.error('config.json 需要填写 ossRegion, ossAccessKeyId, ossAccessKeySecret, ossBucket')
    process.exit(1)
  }
  return config
}

function createClient(config) {
  return new OSS({
    region: config.ossRegion,
    accessKeyId: config.ossAccessKeyId,
    accessKeySecret: config.ossAccessKeySecret,
    bucket: config.ossBucket,
    secure: true,
  })
}

// ============================================================================
// 上传
// ============================================================================

async function uploadFile(filePath, options = {}) {
  const config = getConfig()
  const client = createClient(config)

  if (!fs.existsSync(filePath)) {
    throw new Error(`文件不存在: ${filePath}`)
  }

  const folder = options.folder || config.ossFolder || 'tmp/'
  const basename = options.name || path.basename(filePath)
  const ossPath = `${folder}${basename}`

  const buffer = fs.readFileSync(filePath)
  await client.put(ossPath, buffer)

  const expires = config.ossExpires || 31536000
  const url = client.signatureUrl(ossPath, { expires })

  return { url, ossPath, size: buffer.length }
}

async function uploadBuffer(buffer, options = {}) {
  const config = getConfig()
  const client = createClient(config)

  const folder = options.folder || config.ossFolder || 'tmp/'
  const basename = options.name || `${Date.now()}${options.ext || '.png'}`
  const ossPath = `${folder}${basename}`

  await client.put(ossPath, buffer)

  const expires = config.ossExpires || 31536000
  const url = client.signatureUrl(ossPath, { expires })

  return { url, ossPath }
}

// ============================================================================
// 批量上传（读 manifest.json 中的 file 列表）
// ============================================================================

async function batchUpload(manifestPath, baseDir) {
  const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'))
  const dir = baseDir || path.dirname(manifestPath)
  const results = {}

  for (const item of manifest.items) {
    const filePath = path.join(dir, item.file)
    if (!fs.existsSync(filePath)) continue

    const name = path.basename(item.file)
    try {
      const { url } = await uploadFile(filePath, { name })
      results[item.file] = url
      console.log(`  OK: ${name}`)
    } catch (err) {
      console.error(`  FAIL: ${name} - ${err.message}`)
    }
  }

  return results
}

// ============================================================================
// CLI
// ============================================================================

function parseArgs(argv) {
  const args = { _: [] }
  for (let i = 0; i < argv.length; i++) {
    if (argv[i].startsWith('--')) {
      const key = argv[i].slice(2)
      const val = argv[i + 1]
      if (val && !val.startsWith('--')) { args[key] = val; i++ }
      else args[key] = true
    } else {
      args._.push(argv[i])
    }
  }
  return args
}

async function main() {
  const args = parseArgs(process.argv.slice(2))
  const cmd = args._[0]

  if (!cmd) {
    console.log('用法: node oss-upload.js <file> [--dir folder] [--name filename]')
    console.log('      node oss-upload.js batch <manifest.json> [--dir <baseDir>]')
    process.exit(0)
  }

  if (cmd === 'batch') {
    const manifest = args._[1]
    if (!manifest) { console.error('指定 manifest.json'); process.exit(1) }
    console.log(`批量上传: ${manifest}`)
    const results = await batchUpload(manifest, args.dir)
    console.log(`\n完成: ${Object.keys(results).length} 个文件`)
    // 写回 urls
    const urlsPath = path.join(args.dir || path.dirname(manifest), 'urls.json')
    const existing = fs.existsSync(urlsPath) ? JSON.parse(fs.readFileSync(urlsPath, 'utf-8')) : {}
    Object.assign(existing, results)
    fs.writeFileSync(urlsPath, JSON.stringify(existing, null, 2))
    console.log(`URLs 已写入: ${urlsPath}`)
  } else {
    const filePath = path.resolve(cmd)
    console.log(`上传: ${filePath}`)
    const { url, ossPath, size } = await uploadFile(filePath, {
      folder: args.dir,
      name: args.name,
    })
    console.log(`\nOSS 路径: ${ossPath}`)
    console.log(`签名 URL: ${url}`)
    console.log(`文件大小: ${(size / 1024).toFixed(1)} KB`)
  }
}

module.exports = { uploadFile, uploadBuffer, batchUpload }

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