import express from 'express';
import ffmpeg from 'fluent-ffmpeg';
import axios from 'axios';
import { v4 as uuidv4 } from 'uuid';
import { promises as fs } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const router = express.Router();

// 临时文件目录
const TEMP_DIR = path.join(__dirname, '../temp');

// 确保临时目录存在
async function ensureTempDir() {
  try {
    await fs.mkdir(TEMP_DIR, { recursive: true });
  } catch (err) {
    console.error('创建临时目录失败:', err);
  }
}

ensureTempDir();

/**
 * 下载资源到本地
 */
async function downloadResource(url, outputPath) {
  // 处理 base64 图片 (data:image/svg+xml,...)
  if (url.startsWith('data:')) {
    const matches = url.match(/^data:image\/(\w+);base64,(.+)$/);
    if (matches) {
      const buffer = Buffer.from(matches[2], 'base64');
      await fs.writeFile(outputPath, buffer);
      return outputPath;
    }
    // 处理 URL 编码的 SVG
    if (url.startsWith('data:image/svg+xml,')) {
      const svgContent = decodeURIComponent(url.replace('data:image/svg+xml,', ''));
      await fs.writeFile(outputPath, svgContent);
      return outputPath;
    }
    throw new Error('不支持的 base64 格式');
  }
  
  // 处理普通 HTTP URL
  const response = await axios({
    method: 'GET',
    url: url,
    responseType: 'arraybuffer',
    timeout: 60000,
  });
  
  await fs.writeFile(outputPath, response.data);
  return outputPath;
}

/**
 * 获取音频时长
 */
function getAudioDuration(audioPath) {
  return new Promise((resolve, reject) => {
    ffmpeg.ffprobe(audioPath, (err, metadata) => {
      if (err) {
        reject(err);
        return;
      }
      const duration = metadata.format.duration;
      resolve(duration);
    });
  });
}

/**
 * 合成单个视频片段
 */
async function composeSegment(imagePath, audioPath, outputPath, width, height) {
  const audioDuration = await getAudioDuration(audioPath);
  
  return new Promise((resolve, reject) => {
    ffmpeg()
      .input(imagePath)
      .loop(1)
      .input(audioPath)
      .outputOptions([
        '-tune stillimage',
        '-c:a aac',
        '-b:a 192k',
        '-pix_fmt yuv420p',
        '-shortest'
      ])
      .videoFilter(`scale=${width}:${height}:force_original_aspect_ratio=decrease,pad=${width}:${height}:(ow-iw)/2:(oh-ih)/2`)
      .duration(audioDuration + 0.5)
      .output(outputPath)
      .on('start', (commandLine) => {
        console.log('FFmpeg 命令:', commandLine);
      })
      .on('end', () => resolve(outputPath))
      .on('error', (err, stdout, stderr) => {
        console.error('FFmpeg 错误输出:', stderr);
        reject(err);
      })
      .run();
  });
}

/**
 * 合并多个视频片段
 */
async function mergeSegments(segmentPaths, outputPath) {
  const listPath = path.join(TEMP_DIR, `concat_${uuidv4()}.txt`);
  // Windows 路径需要转义反斜杠或使用正斜杠
  const listContent = segmentPaths.map(p => {
    // 将反斜杠替换为正斜杠，FFmpeg 更兼容
    const normalizedPath = p.replace(/\\/g, '/');
    return `file '${normalizedPath}'`;
  }).join('\n');
  
  await fs.writeFile(listPath, listContent);
  console.log('合并列表内容:\n', listContent);
  
  return new Promise((resolve, reject) => {
    ffmpeg()
      .input(listPath)
      .inputOptions(['-f concat', '-safe 0'])
      .outputOptions(['-c copy'])
      .output(outputPath)
      .on('start', (commandLine) => {
        console.log('FFmpeg 合并命令:', commandLine);
      })
      .on('end', async () => {
        // 清理列表文件
        try {
          await fs.unlink(listPath);
        } catch (e) {
          console.error('清理列表文件失败:', e);
        }
        resolve(outputPath);
      })
      .on('error', (err, stdout, stderr) => {
        console.error('FFmpeg 合并错误:', stderr);
        reject(err);
      })
      .run();
  });
}

/**
 * POST /api/video/compose
 * 合成视频
 * 
 * Body: {
 *   slides: [{ imageUrl, audioUrl }],
 *   width: 1920,
 *   height: 1080
 * }
 */
router.post('/compose', async (req, res) => {
  const { slides, width = 1920, height = 1080 } = req.body;
  
  if (!slides || !Array.isArray(slides) || slides.length === 0) {
    return res.status(400).json({ error: '缺少 slides 参数或格式错误' });
  }
  
  const taskId = uuidv4();
  const taskDir = path.join(TEMP_DIR, taskId);
  
  console.log(`[${taskId}] 开始处理视频合成任务，共 ${slides.length} 个片段`);
  
  try {
    // 创建任务目录
    await fs.mkdir(taskDir, { recursive: true });
    
    const segmentPaths = [];
    
    // 逐个处理片段
    for (let i = 0; i < slides.length; i++) {
      const slide = slides[i];
      console.log(`[${taskId}] 处理第 ${i + 1}/${slides.length} 个片段`);
      
      if (!slide.imageUrl || !slide.audioUrl) {
        console.warn(`[${taskId}] 第 ${i + 1} 个片段缺少 imageUrl 或 audioUrl，跳过`);
        continue;
      }
      
      // 下载图片和音频
      const imagePath = path.join(taskDir, `image_${i}.png`);
      const audioPath = path.join(taskDir, `audio_${i}.mp3`);
      const segmentPath = path.join(taskDir, `segment_${i}.mp4`);
      
      console.log(`[${taskId}] 下载图片: ${slide.imageUrl.substring(0, 50)}...`);
      console.log(`[${taskId}] 下载音频: ${slide.audioUrl.substring(0, 50)}...`);
      
      await downloadResource(slide.imageUrl, imagePath);
      await downloadResource(slide.audioUrl, audioPath);
      
      // 检查文件是否成功创建
      try {
        const imageStats = await fs.stat(imagePath);
        const audioStats = await fs.stat(audioPath);
        console.log(`[${taskId}] 图片大小: ${imageStats.size} bytes, 音频大小: ${audioStats.size} bytes`);
      } catch (e) {
        console.error(`[${taskId}] 文件检查失败:`, e);
      }
      
      // 合成片段
      await composeSegment(imagePath, audioPath, segmentPath, width, height);
      segmentPaths.push(segmentPath);
      
      console.log(`[${taskId}] 第 ${i + 1} 个片段合成完成`);
    }
    
    if (segmentPaths.length === 0) {
      throw new Error('没有有效的片段可以合并');
    }
    
    // 合并所有片段
    console.log(`[${taskId}] 开始合并 ${segmentPaths.length} 个片段`);
    const finalPath = path.join(taskDir, 'output.mp4');
    await mergeSegments(segmentPaths, finalPath);
    
    console.log(`[${taskId}] 视频合成完成: ${finalPath}`);
    
    // 返回视频文件
    res.setHeader('Content-Type', 'video/mp4');
    res.setHeader('Content-Disposition', 'attachment; filename="question-explanation.mp4"');
    
    const videoBuffer = await fs.readFile(finalPath);
    res.send(videoBuffer);
    
    // 清理临时文件（延迟删除，确保响应已发送）
    setTimeout(async () => {
      try {
        await fs.rm(taskDir, { recursive: true, force: true });
        console.log(`[${taskId}] 临时文件已清理`);
      } catch (e) {
        console.error(`[${taskId}] 清理临时文件失败:`, e);
      }
    }, 1000);
    
  } catch (error) {
    console.error(`[${taskId}] 视频合成失败:`, error);
    
    // 清理临时文件
    try {
      await fs.rm(taskDir, { recursive: true, force: true });
    } catch (e) {
      // 忽略清理错误
    }
    
    res.status(500).json({ 
      error: '视频合成失败', 
      message: error.message 
    });
  }
});

/**
 * GET /api/video/health
 * 检查视频服务状态
 */
router.get('/health', (req, res) => {
  // 检查 ffmpeg 是否可用
  ffmpeg.getAvailableFormats((err, formats) => {
    if (err) {
      return res.status(500).json({ 
        status: 'error', 
        message: 'FFmpeg 不可用',
        error: err.message 
      });
    }
    
    res.json({ 
      status: 'ok', 
      message: '视频合成服务正常运行',
      formats: formats ? Object.keys(formats).length : 'unknown'
    });
  });
});

export default router;
