/**
 * 视频下载器 - 基于浏览器自动化+API拦截方案
 * 替换原有的在线API分析，实现真正的视频内容下载和识别
 */

import { app } from 'electron';
import path from 'path';
import fs from 'fs';
import http from 'http';
import https from 'https';
import { Page, BrowserContext } from 'playwright';
import { DouyinBrowserManager } from './browserManager';

interface VideoInfo {
  aweme_id: string;
  desc: string;
  author: {
    uid: string;
    nickname: string;
  };
  video: {
    play_addr: {
      url_list: string[];
    };
    duration: number;
  };
}

interface DownloadResult {
  success: boolean;
  videoPath?: string;
  audioPath?: string;
  videoInfo?: VideoInfo;
  error?: string;
}

class DouyinVideoDownloader {
  private static readonly DIRECT_VIDEO_PATTERN = /https?:\/\/[^\s"'<>]+?\.(mp4|mov|m4v|webm|avi|mkv)(\?[^\s"'<>]*)?/i;
  private browserManager: DouyinBrowserManager;
  private externalContext: BrowserContext | null; // 外部传入的浏览器上下文
  private userDataPath: string;

  constructor(externalContext?: BrowserContext) {
    this.externalContext = externalContext || null;
    this.browserManager = DouyinBrowserManager.getInstance();
    // 设置用户数据目录以保持登录状态
    this.userDataPath = path.join(app.getPath('userData'), 'douyin-browser-data');
  }

  private getDownloadDir(): string {
    const downloadDir = path.join(app.getPath('userData'), 'downloads', 'videos');
    if (!fs.existsSync(downloadDir)) {
      fs.mkdirSync(downloadDir, { recursive: true });
    }
    return downloadDir;
  }

  private inferVideoExtension(videoUrl: string): string {
    try {
      const pathname = new URL(videoUrl).pathname.toLowerCase();
      const matchedExt = pathname.match(/\.(mp4|mov|m4v|webm|avi|mkv)$/i)?.[1]?.toLowerCase();
      if (matchedExt) {
        return `.${matchedExt}`;
      }
    } catch (error) {
      console.warn('inferVideoExtension failed:', error);
    }

    return '.mp4';
  }

  private isDirectVideoUrl(videoUrl: string): boolean {
    return DouyinVideoDownloader.DIRECT_VIDEO_PATTERN.test(videoUrl.trim());
  }

  private downloadRemoteFile(
    fileUrl: string,
    savePath: string,
    headers: Record<string, string>,
    redirectCount: number = 0
  ): Promise<void> {
    return new Promise((resolve, reject) => {
      if (redirectCount > 5) {
        reject(new Error('Too many redirects while downloading video'));
        return;
      }

      const client = fileUrl.startsWith('https://') ? https : http;
      const fileStream = fs.createWriteStream(savePath);
      let settled = false;

      const fail = (error: Error) => {
        if (settled) {
          return;
        }
        settled = true;
        fileStream.destroy();
        if (fs.existsSync(savePath)) {
          fs.unlinkSync(savePath);
        }
        reject(error);
      };

      const request = client.get(fileUrl, { headers }, (response) => {
        const statusCode = response.statusCode ?? 0;
        const location = response.headers.location;

        if (statusCode >= 300 && statusCode < 400 && location) {
          fileStream.close();
          fs.unlinkSync(savePath);
          const redirectUrl = location.startsWith('http')
            ? location
            : new URL(location, fileUrl).toString();
          this.downloadRemoteFile(redirectUrl, savePath, headers, redirectCount + 1)
            .then(resolve)
            .catch(reject);
          return;
        }

        if (statusCode !== 200) {
          fail(new Error(`HTTP ${statusCode}: ${response.statusMessage}`));
          return;
        }

        response.pipe(fileStream);

        fileStream.on('finish', () => {
          if (settled) {
            return;
          }
          settled = true;
          fileStream.close();
          resolve();
        });
      });

      request.on('error', (error) => {
        fail(error);
      });

      fileStream.on('error', (error) => {
        request.destroy();
        fail(error);
      });

      request.setTimeout(120000, () => {
        request.destroy();
        fail(new Error('Download timed out after 120 seconds'));
      });
    });
  }

  /**
   * 初始化浏览器（使用管理器或外部上下文）
   */
  async initBrowser(): Promise<void> {
    // 如果有外部提供的Context，则不需要初始化
    if (this.externalContext) {
      console.log('使用外部提供的浏览器上下文');
      return;
    }

    // 否则使用内部管理器
    await this.browserManager.initBrowser();
  }

  /**
   * 从视频URL提取aweme_id（支持短链接重定向）
   */
  async extractAwemeIdAsync(url: string): Promise<string | null> {
    // 标准化URL格式
    let normalizedUrl = url.trim();
    if (!normalizedUrl.startsWith('http')) {
      normalizedUrl = 'https://' + normalizedUrl;
    }

    console.log('标准化URL:', normalizedUrl);

    // 支持多种抖音URL格式
    const patterns = [
      /\/video\/(\d+)/,
      /modal_id=(\d+)/,
      /share\/video\/(\d+)/,
      /item_id=(\d+)/,
      /aweme_id=(\d+)/,
    ];

    for (const pattern of patterns) {
      const match = normalizedUrl.match(pattern);
      if (match) {
        console.log('提取到aweme_id:', match[1]);
        return match[1];
      }
    }

    // 如果是短链接（v.douyin.com），需要请求获取重定向后的真实URL
    if (normalizedUrl.includes('v.douyin.com') || normalizedUrl.includes('iesdouyin.com')) {
      console.log('检测到短链接，尝试获取重定向后的真实URL...');
      try {
        const realUrl = await this.resolveShortUrl(normalizedUrl);
        if (realUrl && realUrl !== normalizedUrl) {
          console.log('重定向后的真实URL:', realUrl);
          // 再次尝试从真实URL提取ID
          for (const pattern of patterns) {
            const match = realUrl.match(pattern);
            if (match) {
              console.log('从重定向URL提取到aweme_id:', match[1]);
              return match[1];
            }
          }
        }
      } catch (error) {
        console.error('解析短链接失败:', error);
      }
    }

    console.log('未能提取aweme_id，URL格式可能不支持');
    return null;
  }

  /**
   * 解析短链接获取重定向后的真实URL
   */
  private resolveShortUrl(shortUrl: string): Promise<string> {
    return new Promise((resolve, reject) => {
      const url = new URL(shortUrl);
      const options = {
        hostname: url.hostname,
        path: url.pathname + url.search,
        method: 'HEAD',
        headers: {
          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
        },
        timeout: 30000  // 增加短链接解析超时到30秒
      };

      const req = https.request(options, (res) => {
        // 如果有重定向，返回重定向的URL
        if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
          resolve(res.headers.location);
        } else {
          // 没有重定向，返回原URL
          resolve(shortUrl);
        }
      });

      req.on('error', (error) => {
        console.error('请求短链接失败:', error);
        reject(error);
      });

      req.on('timeout', () => {
        req.destroy();
        reject(new Error('短链接解析超时'));
      });

      req.end();
    });
  }

  /**
   * 同步版本的ID提取（兼容旧代码）
   */
  extractAwemeId(url: string): string | null {
    // 标准化URL格式
    let normalizedUrl = url.trim();
    if (!normalizedUrl.startsWith('http')) {
      normalizedUrl = 'https://' + normalizedUrl;
    }

    console.log('标准化URL:', normalizedUrl);

    // 支持多种抖音URL格式
    const patterns = [
      /\/video\/(\d+)/,
      /modal_id=(\d+)/,
      /share\/video\/(\d+)/,
      /item_id=(\d+)/,
      /aweme_id=(\d+)/,
    ];

    for (const pattern of patterns) {
      const match = normalizedUrl.match(pattern);
      if (match) {
        console.log('提取到aweme_id:', match[1]);
        return match[1];
      }
    }

    // 对于短链接，返回null让调用者使用异步版本
    if (normalizedUrl.includes('v.douyin.com') || normalizedUrl.includes('iesdouyin.com')) {
      console.log('检测到短链接，需要使用异步方法解析');
      return null;
    }

    console.log('未能提取aweme_id，URL格式可能不支持');
    return null;
  }

  /**
   * 拦截API响应获取视频信息
   */
  async interceptVideoInfo(page: Page, awemeId: string): Promise<VideoInfo | null> {
    return new Promise((resolve) => {
      let found = false;

      // 监听API响应
      page.on('response', async (response) => {
        if (found) return;

        const url = response.url();

        // 拦截视频详情API
        if (url.includes('aweme/v1/web/aweme/detail') && url.includes(awemeId)) {
          try {
            const text = await response.text();
            console.log('API响应:', text.substring(0, 200));

            // 处理可能的响应格式
            let data: any;
            try {
              data = JSON.parse(text);
            } catch {
              // 尝试处理带前缀的响应
              const jsonStr = text.replace(/^[^{]*/, '');
              data = JSON.parse(jsonStr);
            }

            if (data.aweme_detail) {
              found = true;
              resolve(data.aweme_detail as VideoInfo);
            }
          } catch (error) {
            console.error('解析API响应失败:', error);
          }
        }
      });

      // 设置超时（增加到30秒，给API足够的时间响应）
      setTimeout(() => {
        if (!found) {
          console.log('API拦截超时，将尝试其他方法获取视频信息');
          resolve(null);
        }
      }, 30000);
    });
  }

  /**
   * 下载视频文件
   */
  async downloadVideo(videoUrl: string, savePath: string): Promise<void> {
    const headers = {
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
      'Referer': 'https://www.douyin.com/',
      'Accept': '*/*',
      'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
      'Accept-Encoding': 'gzip, deflate, br'
    };

    return this.downloadRemoteFile(videoUrl, savePath, headers);
  }

  async downloadDirectVideo(videoUrl: string): Promise<DownloadResult> {
    try {
      if (!this.isDirectVideoUrl(videoUrl)) {
        return {
          success: false,
          error: 'Unsupported direct video url'
        };
      }

      const downloadDir = this.getDownloadDir();
      const extension = this.inferVideoExtension(videoUrl);
      const videoPath = path.join(downloadDir, `direct_${Date.now()}${extension}`);

      const headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        'Accept': '*/*',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'
      };

      await this.downloadRemoteFile(videoUrl, videoPath, headers);

      return {
        success: true,
        videoPath,
        audioPath: videoPath.replace(path.extname(videoPath), '_audio.wav')
      };
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : String(error)
      };
    }
  }

  /**
   * 下载抖音视频
   */
  async downloadDouyinVideo(videoUrl: string): Promise<DownloadResult> {
    let page: Page | null = null;
    let browserInitialized = false;

    try {
      console.log('开始下载抖音视频:', videoUrl);

      // 提取视频ID（使用异步版本支持短链接重定向）
      const awemeId = await this.extractAwemeIdAsync(videoUrl);
      if (!awemeId) {
        return { success: false, error: '无法从URL中提取视频ID，请检查链接格式' };
      }

      console.log('提取到视频ID:', awemeId);

      // 创建下载目录
      const downloadDir = path.join(app.getPath('userData'), 'downloads', 'videos');
      if (!fs.existsSync(downloadDir)) {
        fs.mkdirSync(downloadDir, { recursive: true });
      }

      // 设置下载路径
      const videoFileName = `douyin_${awemeId}_${Date.now()}.mp4`;
      const videoPath = path.join(downloadDir, videoFileName);
      console.log('视频保存路径:', videoPath);

      try {
        // 初始化浏览器（使用管理器或外部上下文）
        console.log('初始化浏览器...');
        await this.initBrowser();

        // 使用外部Context或内部管理器创建页面
        if (this.externalContext) {
          page = await this.externalContext.newPage();
          console.log('使用外部浏览器上下文创建页面成功');
        } else {
          page = await this.browserManager.newPage();
          console.log('使用内部浏览器管理器创建页面成功');
        }

        // 设置页面超时和错误处理
        page.setDefaultTimeout(60000); // 增加超时时间到60秒

        // 监听页面关闭事件
        page.on('close', () => {
          console.log('页面已关闭');
          page = null;
        });

        // 不再强制前置登录检查 - 公开视频无需登录即可访问
        // 只在真正跳转到登录页时才引导用户登录
        console.log('准备拦截视频信息...');

        // 拦截视频信息（先注册监听，再导航）
        const videoInfoPromise = this.interceptVideoInfo(page, awemeId);

        // 直接构造标准视频URL（避免短链接重定向到 jingxuan+modal_id 不触发API）
        // 由于 awemeId 已经提取，直接访问 /video/{awemeId} 标准路径
        const directVideoUrl = `https://www.douyin.com/video/${awemeId}`;
        console.log('访问视频页面（标准路径）:', directVideoUrl);

        try {
          await page.goto(directVideoUrl, {
            waitUntil: 'domcontentloaded',
            timeout: 30000
          });
          console.log('页面DOM加载完成');

          const currentUrl = page.url();
          console.log('当前页面URL:', currentUrl);

          // 只有跳到真正的 /login 页面才引导登录
          const isLoginPage = currentUrl.includes('/login') || currentUrl.includes('login?');

          if (isLoginPage) {
            console.log('⚠️ 页面跳转到了登录页，开始引导登录...');
            await this.ensureLoggedIn(page);

            console.log('登录后重新访问视频页面...');
            await page.goto(directVideoUrl, {
              waitUntil: 'domcontentloaded',
              timeout: 30000
            });

            const retryUrl = page.url();
            console.log('重试后的页面URL:', retryUrl);
            if (retryUrl.includes('/login')) {
              return { success: false, error: '无法访问视频页面，请先扫码登录抖音后重试' };
            }
          } else if (currentUrl.includes('/video/')) {
            console.log('✅ 视频页面加载成功，等待API响应...');
          } else {
            console.log('⚠️ 页面重定向到:', currentUrl, '，继续等待API响应...');
          }
        } catch (gotoError) {
          console.log('页面goto超时（已忽略），继续等待API响应:', gotoError instanceof Error ? gotoError.message : gotoError);
        }

        console.log('等待API响应...');

        // 获取视频信息
        const videoInfo = await videoInfoPromise;

        if (!videoInfo) {
          console.log('未获取到视频信息，尝试其他方法...');

          // 备用方法：尝试直接从页面获取信息
          try {
            const pageContent = await page.content();
            console.log('页面内容长度:', pageContent.length);

            // 如果页面内容包含视频信息，尝试解析
            if (pageContent.includes('aweme_detail')) {
              // 简单的备用处理
              return {
                success: true,
                videoPath,
                videoInfo: {
                  aweme_id: awemeId,
                  desc: `抖音视频 ${awemeId}`,
                  author: { uid: '', nickname: '未知作者' },
                  video: {
                    play_addr: { url_list: [] },
                    duration: 0
                  }
                },
                audioPath: videoPath.replace('.mp4', '_audio.wav')
              };
            }
          } catch (pageError) {
            console.error('页面解析失败:', pageError);
          }

          return { success: false, error: '无法获取视频信息，可能视频不存在或访问受限' };
        }

        console.log('获取到视频信息:', videoInfo.desc);

        // 获取视频下载链接
        const videoUrls = videoInfo.video?.play_addr?.url_list;
        if (!videoUrls || videoUrls.length === 0) {
          return { success: false, error: '无法获取视频下载链接，可能视频版权限制' };
        }

        const downloadUrl = videoUrls[0];
        console.log('找到下载链接:', downloadUrl.substring(0, 100) + '...');

        // 下载视频文件
        console.log('开始下载视频文件...');
        await this.downloadVideo(downloadUrl, videoPath);

        console.log('视频下载完成:', videoPath);
        console.log('文件大小:', fs.statSync(videoPath).size, 'bytes');

        return {
          success: true,
          videoPath,
          videoInfo,
          audioPath: videoPath.replace('.mp4', '_audio.wav')
        };

      } finally {
        // 页面处理完成，关闭页面
        if (page) {
          try {
            console.log('关闭页面...');
            await page.close();
            console.log('页面已关闭');
          } catch (closeError) {
            console.log('页面关闭时出错:', closeError instanceof Error ? closeError.message : closeError);
          }
        }
      }

    } catch (error) {
      console.error('下载视频失败:', error);

      let errorMessage = '未知错误';
      if (error instanceof Error) {
        errorMessage = error.message;

        if (errorMessage.includes('3221225781') || errorMessage.includes('0xC0000135') || errorMessage.includes('0xc0000135')) {
          errorMessage = '浏览器启动失败（错误码: 0xC0000135）。\n' +
            '可能原因：\n' +
            '1. 系统缺少 Visual C++ 运行时库，请安装: https://aka.ms/vs/17/release/vc_redist.x64.exe\n' +
            '2. 系统版本过低，Chromium 要求 Windows 10 或更高版本\n' +
            '3. 杀毒软件拦截了浏览器进程\n' +
            '安装 VC++ 运行库后重启应用即可。';
        } else if (errorMessage.includes('playwright') || errorMessage.includes('browser')) {
          errorMessage = '浏览器启动失败，请检查系统环境和权限设置';
        } else if (errorMessage.includes('timeout')) {
          errorMessage = '网络超时，请检查网络连接或重试';
        } else if (errorMessage.includes('404') || errorMessage.includes('403')) {
          errorMessage = '视频不存在或访问受限';
        }
      }

      return {
        success: false,
        error: errorMessage
      };
    }
  }

  /**
   * 引导用户登录（只在真正需要时调用）
   * 基于Cookie检测是否已登录，未登录则引导扫码
   */
  async ensureLoggedIn(page: Page): Promise<void> {
    try {
      // 如果是外部浏览器上下文（来自已登录的UI），直接信任其登录状态
      if (this.externalContext) {
        console.log('✅ 使用外部已登录的浏览器上下文，跳过登录检查');
        return;
      }

      // 先通过Cookie快速判断是否已登录（避免重新访问首页）
      try {
        const cookies = await page.context().cookies(['https://www.douyin.com']);
        const loginCookies = cookies.filter(c =>
          ['sessionid', 'uid_tt', 'LOGIN_STATUS', 'sid_guard', 'sid_tt'].includes(c.name) && c.value
        );
        if (loginCookies.length > 0) {
          console.log('✅ 检测到已登录Cookie，无需重新登录');
          return;
        }
      } catch (e) {
        // Cookie检测失败，继续走DOM检测
      }

      // Cookie不存在，访问首页检测登录状态
      console.log('检查登录状态，开始访问抖音首页...');
      await page.goto('https://www.douyin.com/', {
        waitUntil: 'domcontentloaded',
        timeout: 30000
      });
      console.log('抖音首页加载完成，等待页面元素...');
      try {
        await page.waitForSelector('body', { timeout: 10000 });
      } catch (e) {
        console.log('页面加载超时，继续执行');
      }
      await page.waitForTimeout(2000);

      // 通过DOM元素检测登录状态
      const isLoggedIn = await page.evaluate(() => {
        // 检测登录按钮（未登录时出现）
        const loginBtnSelectors = [
          '[data-e2e="login-button"]',
          '.login-btn',
          '.e2e-login-btn',
          'button[class*="login"]'
        ];
        // 检测用户信息（已登录时出现）
        const userInfoSelectors = [
          '[data-e2e="user-info"]',
          '[data-e2e="user-avatar"]',
          '[class*="userInfo"]',
          '[class*="UserInfo"]',
          '[class*="avatar"]',
          '.user-name',
          '.header-user',
          '.user-avatar',
          '.nickname'
        ];
        const hasLoginButton = loginBtnSelectors.some(s => document.querySelector(s));
        const hasUserInfo = userInfoSelectors.some(s => document.querySelector(s));
        // 如果有用户信息，或者没有登录按钮，认为已登录
        return hasUserInfo || !hasLoginButton;
      });

      if (isLoggedIn) {
        console.log('✅ 用户已登录');
        return;
      }

      console.log('❌ 用户未登录，开始引导登录...');
      console.log('='.repeat(60));
      console.log('📱 请在浏览器中扫码登录抖音');
      console.log('='.repeat(60));
      console.log('1. ✅ 浏览器窗口已打开');
      console.log('2. 📱 请使用抖音APP扫描页面上的二维码');
      console.log('3. ✅ 登录成功后会自动继续处理');
      console.log('4. ⏰ 登录超时时间：2分钟');
      console.log('='.repeat(60));

      // 等待登录（最多2分钟）
      let loginSuccess = false;
      const loginTimeout = 120000;
      const checkInterval = 3000;
      const startTime = Date.now();

      while (Date.now() - startTime < loginTimeout) {
        await page.waitForTimeout(checkInterval);
        const cookies = await page.context().cookies(['https://www.douyin.com']);
        const loginCookies = cookies.filter(c =>
          ['sessionid', 'uid_tt', 'LOGIN_STATUS', 'sid_guard'].includes(c.name) && c.value
        );
        if (loginCookies.length > 0) {
          loginSuccess = true;
          console.log('✅ 登录成功，继续处理...');
          break;
        }
      }

      if (!loginSuccess) {
        console.log('⚠️ 登录超时，以未登录状态继续尝试...');
      }

      // 保存登录状态
      try {
        const statePath = path.join(this.userDataPath, 'douyin-state.json');
        await page.context().storageState({ path: statePath });
      } catch (e) { }

    } catch (error) {
      console.error('登录引导失败:', error);
      // 继续执行
    }
  }

  /**
   * 保存当前浏览器状态
   */
  async saveBrowserState(): Promise<void> {
    try {
      const statePath = path.join(this.userDataPath, 'douyin-state.json');
      const { context } = this.browserManager.getBrowserInfo();
      if (context) {
        await context.storageState({ path: statePath });
        console.log('浏览器状态已保存到:', statePath);
      }
    } catch (error) {
      console.error('保存浏览器状态失败:', error);
    }
  }

  /**
   * 关闭浏览器
   */
  async close(): Promise<void> {
    // 如果使用的是外部提供的Context，不要关闭它，由调用者管理
    if (this.externalContext) {
      console.log('使用外部浏览器上下文，不关闭浏览器（由调用者管理）');
      return;
    }

    try {
      await this.browserManager.close();
    } catch (error) {
      console.error('关闭浏览器失败:', error);
    }

    // 🔧 关键修复：无论如何都要强制杀死 Chromium 进程（确保浏览器真的关闭）
    // [临时禁用] 暂时注释掉强制杀死浏览器进程的逻辑
    /*
    try {
      const { execSync } = require('child_process');
      execSync('taskkill /F /IM chrome.exe /IM chromium.exe 2>nul', { shell: true });
      console.log('✅ 已强制杀死所有 Chromium 进程');
    } catch (killError) {
      console.log('杀死进程失败（忽略）:', killError);
    }
    */
  }
}

export { DouyinVideoDownloader, VideoInfo, DownloadResult };
