/// <reference lib="dom" />
import path from 'path';
import { BasePlatformAdapter } from './base.js';
import type {
  AccountProfile,
  PublishParams,
  PublishResult,
  DateRange,
  AnalyticsData,
  CommentData,
} from './base.js';
import type { PlatformType, QRCodeInfo, LoginStatusResult } from '@media-manager/shared';
import { logger } from '../../utils/logger.js';
import { aiService } from '../../ai/index.js';

// Python 多平台发布服务配置
const PYTHON_PUBLISH_SERVICE_URL = process.env.PYTHON_PUBLISH_SERVICE_URL || process.env.XHS_SERVICE_URL || 'http://localhost:5005';

// 服务器根目录（用于构造绝对路径）
const SERVER_ROOT = path.resolve(process.cwd());

/**
 * 微信视频号平台适配器
 * 参考: matrix/tencent_uploader/main.py
 */
export class WeixinAdapter extends BasePlatformAdapter {
  readonly platform: PlatformType = 'weixin_video';
  readonly loginUrl = 'https://channels.weixin.qq.com/platform';
  readonly publishUrl = 'https://channels.weixin.qq.com/platform/post/create';
  
  protected getCookieDomain(): string {
    return '.weixin.qq.com';
  }
  
  async getQRCode(): Promise<QRCodeInfo> {
    try {
      await this.initBrowser();
      
      if (!this.page) throw new Error('Page not initialized');
      
      // 访问登录页面
      await this.page.goto('https://channels.weixin.qq.com/platform/login-for-iframe?dark_mode=true&host_type=1');
      
      // 点击二维码切换
      await this.page.locator('.qrcode').click();
      
      // 获取二维码
      const qrcodeImg = await this.page.locator('img.qrcode').getAttribute('src');
      
      if (!qrcodeImg) {
        throw new Error('Failed to get QR code');
      }
      
      return {
        qrcodeUrl: qrcodeImg,
        qrcodeKey: `weixin_${Date.now()}`,
        expireTime: Date.now() + 300000,
      };
    } catch (error) {
      logger.error('Weixin getQRCode error:', error);
      throw error;
    }
  }
  
  async checkQRCodeStatus(qrcodeKey: string): Promise<LoginStatusResult> {
    try {
      if (!this.page) {
        return { status: 'expired', message: '二维码已过期' };
      }
      
      // 检查是否扫码成功
      const maskDiv = this.page.locator('.mask').first();
      const className = await maskDiv.getAttribute('class');
      
      if (className && className.includes('show')) {
        // 等待登录完成
        await this.page.waitForTimeout(3000);
        
        const cookies = await this.getCookies();
        if (cookies && cookies.length > 10) {
          await this.closeBrowser();
          return { status: 'success', message: '登录成功', cookies };
        }
      }
      
      return { status: 'waiting', message: '等待扫码' };
    } catch (error) {
      logger.error('Weixin checkQRCodeStatus error:', error);
      return { status: 'error', message: '检查状态失败' };
    }
  }
  
  async checkLoginStatus(cookies: string): Promise<boolean> {
    try {
      await this.initBrowser();
      await this.setCookies(cookies);
      
      if (!this.page) throw new Error('Page not initialized');
      
      await this.page.goto(this.publishUrl);
      await this.page.waitForLoadState('networkidle');
      
      // 检查是否需要登录
      const needLogin = await this.page.$('div.title-name:has-text("视频号小店")');
      await this.closeBrowser();
      
      return !needLogin;
    } catch (error) {
      logger.error('Weixin checkLoginStatus error:', error);
      await this.closeBrowser();
      return false;
    }
  }
  
  /**
   * 关闭页面上可能存在的弹窗对话框
   */
  private async closeModalDialogs(): Promise<boolean> {
    if (!this.page) return false;
    
    let closedAny = false;
    
    try {
      const modalSelectors = [
        // 微信视频号常见弹窗关闭按钮
        '.weui-desktop-dialog__close',
        '.weui-desktop-btn__default:has-text("取消")',
        '.weui-desktop-btn__default:has-text("关闭")',
        '.weui-desktop-dialog-close',
        '[class*="dialog"] [class*="close"]',
        '[class*="modal"] [class*="close"]',
        '[role="dialog"] button[aria-label="close"]',
        'button:has-text("关闭")',
        'button:has-text("取消")',
        'button:has-text("我知道了")',
        '.close-btn',
        '.icon-close',
      ];
      
      for (const selector of modalSelectors) {
        try {
          const closeBtn = this.page.locator(selector).first();
          if (await closeBtn.count() > 0 && await closeBtn.isVisible()) {
            logger.info(`[Weixin] Found modal close button: ${selector}`);
            await closeBtn.click({ timeout: 2000 });
            closedAny = true;
            await this.page.waitForTimeout(500);
          }
        } catch (e) {
          // 忽略错误，继续尝试下一个选择器
        }
      }
      
      // 尝试按 ESC 键关闭弹窗
      if (!closedAny) {
        const hasModal = await this.page.locator('[class*="dialog"], [class*="modal"], [role="dialog"]').count();
        if (hasModal > 0) {
          logger.info('[Weixin] Trying ESC key to close modal...');
          await this.page.keyboard.press('Escape');
          await this.page.waitForTimeout(500);
          closedAny = true;
        }
      }
      
      if (closedAny) {
        logger.info('[Weixin] Successfully closed modal dialog');
      }
      
    } catch (error) {
      logger.warn('[Weixin] Error closing modal:', error);
    }
    
    return closedAny;
  }

  async getAccountInfo(cookies: string): Promise<AccountProfile> {
    try {
      await this.initBrowser();
      await this.setCookies(cookies);
      
      if (!this.page) throw new Error('Page not initialized');
      
      // 访问视频号创作者平台首页
      await this.page.goto('https://channels.weixin.qq.com/platform/home');
      await this.page.waitForLoadState('networkidle');
      await this.page.waitForTimeout(2000);
      
      // 从页面提取账号信息
      const accountData = await this.page.evaluate(() => {
        const result: { accountId?: string; accountName?: string; avatarUrl?: string; fansCount?: number; worksCount?: number } = {};
        
        try {
          // ===== 1. 优先使用精确选择器获取视频号 ID =====
          // 方法1: 通过 #finder-uid-copy 的 data-clipboard-text 属性获取
          const finderIdCopyEl = document.querySelector('#finder-uid-copy');
          if (finderIdCopyEl) {
            const clipboardText = finderIdCopyEl.getAttribute('data-clipboard-text');
            if (clipboardText && clipboardText.length >= 10) {
              result.accountId = clipboardText;
              console.log('[WeixinVideo] Found finder ID from data-clipboard-text:', result.accountId);
            } else {
              const text = finderIdCopyEl.textContent?.trim();
              if (text && /^[a-zA-Z0-9_]+$/.test(text) && text.length >= 10) {
                result.accountId = text;
                console.log('[WeixinVideo] Found finder ID from #finder-uid-copy text:', result.accountId);
              }
            }
          }
          
          // 方法2: 通过 .finder-uniq-id 选择器获取
          if (!result.accountId) {
            const finderUniqIdEl = document.querySelector('.finder-uniq-id');
            if (finderUniqIdEl) {
              const clipboardText = finderUniqIdEl.getAttribute('data-clipboard-text');
              if (clipboardText && clipboardText.length >= 10) {
                result.accountId = clipboardText;
                console.log('[WeixinVideo] Found finder ID from .finder-uniq-id data-clipboard-text:', result.accountId);
              } else {
                const text = finderUniqIdEl.textContent?.trim();
                if (text && /^[a-zA-Z0-9_]+$/.test(text) && text.length >= 10) {
                  result.accountId = text;
                  console.log('[WeixinVideo] Found finder ID from .finder-uniq-id text:', result.accountId);
                }
              }
            }
          }
          
          // 方法3: 从页面文本中正则匹配
          if (!result.accountId) {
            const bodyText = document.body.innerText || '';
            const finderIdPatterns = [
              /视频号ID[：:\s]*([a-zA-Z0-9_]+)/,
              /视频号[：:\s]*ID[：:\s]*([a-zA-Z0-9_]+)/,
            ];
            for (const pattern of finderIdPatterns) {
              const match = bodyText.match(pattern);
              if (match && match[1] && match[1].length >= 10) {
                result.accountId = match[1];
                console.log('[WeixinVideo] Found finder ID from regex:', result.accountId);
                break;
              }
            }
          }
          
          // ===== 2. 获取账号名称 =====
          const nicknameEl = document.querySelector('h2.finder-nickname') || 
                            document.querySelector('.finder-nickname');
          if (nicknameEl) {
            const text = nicknameEl.textContent?.trim();
            if (text && text.length >= 2 && text.length <= 30) {
              result.accountName = text;
              console.log('[WeixinVideo] Found name:', result.accountName);
            }
          }
          
          // ===== 3. 获取头像 =====
          const avatarEl = document.querySelector('img.avatar') as HTMLImageElement;
          if (avatarEl?.src && avatarEl.src.startsWith('http')) {
            result.avatarUrl = avatarEl.src;
          } else {
            const altAvatarEl = document.querySelector('img[alt="视频号头像"]') as HTMLImageElement;
            if (altAvatarEl?.src && altAvatarEl.src.startsWith('http')) {
              result.avatarUrl = altAvatarEl.src;
            }
          }
          
          // ===== 4. 获取视频数和关注者数 =====
          const contentInfo = document.querySelector('.finder-content-info');
          if (contentInfo) {
            const infoDivs = contentInfo.querySelectorAll('div');
            infoDivs.forEach(div => {
              const text = div.textContent || '';
              const numEl = div.querySelector('.finder-info-num');
              if (numEl) {
                const num = parseInt(numEl.textContent?.trim() || '0', 10);
                if (text.includes('视频') || text.includes('作品')) {
                  result.worksCount = num;
                } else if (text.includes('关注者') || text.includes('粉丝')) {
                  result.fansCount = num;
                }
              }
            });
          }
          
          // 备选：从页面整体文本中匹配
          if (result.fansCount === undefined || result.worksCount === undefined) {
            const bodyText = document.body.innerText || '';
            if (result.fansCount === undefined) {
              const fansMatch = bodyText.match(/关注者\s*(\d+(?:\.\d+)?[万wW]?)/);
              if (fansMatch) {
                let count = parseFloat(fansMatch[1]);
                if (fansMatch[1].includes('万') || fansMatch[1].toLowerCase().includes('w')) {
                  count = count * 10000;
                }
                result.fansCount = Math.floor(count);
              }
            }
            if (result.worksCount === undefined) {
              const worksMatch = bodyText.match(/视频\s*(\d+)/);
              if (worksMatch) {
                result.worksCount = parseInt(worksMatch[1], 10);
              }
            }
          }
        } catch (e) {
          console.error('[WeixinVideo] Extract error:', e);
        }
        
        return result;
      });
      
      logger.info('[Weixin] Extracted account data:', accountData);
      
      // 如果首页没有获取到视频号 ID，尝试访问账号设置页面
      let finalAccountId = accountData.accountId;
      if (!finalAccountId || finalAccountId.length < 10) {
        logger.info('[Weixin] Finder ID not found on home page, trying account settings page...');
        
        try {
          await this.page.goto('https://channels.weixin.qq.com/platform/account');
          await this.page.waitForLoadState('networkidle');
          await this.page.waitForTimeout(2000);
          
          const settingsId = await this.page.evaluate(() => {
            const bodyText = document.body.innerText || '';
            const patterns = [
              /视频号ID[：:\s]*([a-zA-Z0-9_]+)/,
              /视频号[：:\s]*ID[：:\s]*([a-zA-Z0-9_]+)/,
              /唯一标识[：:\s]*([a-zA-Z0-9_]+)/,
            ];
            for (const pattern of patterns) {
              const match = bodyText.match(pattern);
              if (match && match[1]) {
                return match[1];
              }
            }
            return null;
          });
          
          if (settingsId) {
            finalAccountId = settingsId;
            logger.info('[Weixin] Found finder ID from settings page:', finalAccountId);
          }
        } catch (e) {
          logger.warn('[Weixin] Failed to fetch from settings page:', e);
        }
      }
      
      await this.closeBrowser();
      
      return {
        accountId: finalAccountId || `weixin_video_${Date.now()}`,
        accountName: accountData.accountName || '视频号账号',
        avatarUrl: accountData.avatarUrl || '',
        fansCount: accountData.fansCount || 0,
        worksCount: accountData.worksCount || 0,
      };
    } catch (error) {
      logger.error('Weixin getAccountInfo error:', error);
      await this.closeBrowser();
      return {
        accountId: `weixin_video_${Date.now()}`,
        accountName: '视频号账号',
        avatarUrl: '',
        fansCount: 0,
        worksCount: 0,
      };
    }
  }
  
  /**
   * 检查 Python 发布服务是否可用
   */
  private async checkPythonServiceAvailable(): Promise<boolean> {
    try {
      const response = await fetch(`${PYTHON_PUBLISH_SERVICE_URL}/health`, {
        method: 'GET',
        signal: AbortSignal.timeout(3000),
      });
      if (response.ok) {
        const data = await response.json();
        return data.status === 'ok' && data.supported_platforms?.includes('weixin');
      }
      return false;
    } catch {
      return false;
    }
  }

  /**
   * 通过 Python 服务发布视频（带 AI 辅助）
   */
  private async publishVideoViaPython(
    cookies: string,
    params: PublishParams,
    onProgress?: (progress: number, message: string) => void
  ): Promise<PublishResult> {
    logger.info('[Weixin Python] Starting publish via Python service with AI assist...');
    onProgress?.(5, '正在通过 Python 服务发布...');

    try {
      // 将相对路径转换为绝对路径
      const absoluteVideoPath = path.isAbsolute(params.videoPath)
        ? params.videoPath
        : path.resolve(SERVER_ROOT, params.videoPath);

      const absoluteCoverPath = params.coverPath
        ? (path.isAbsolute(params.coverPath) ? params.coverPath : path.resolve(SERVER_ROOT, params.coverPath))
        : undefined;

      // 使用 AI 辅助发布接口
      const response = await fetch(`${PYTHON_PUBLISH_SERVICE_URL}/publish/ai-assisted`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          platform: 'weixin',
          cookie: cookies,
          title: params.title,
          description: params.description || params.title,
          video_path: absoluteVideoPath,
          cover_path: absoluteCoverPath,
          tags: params.tags || [],
          post_time: params.scheduledTime ? new Date(params.scheduledTime).toISOString().replace('T', ' ').slice(0, 19) : null,
          location: params.location || '重庆市',
          return_screenshot: true,
        }),
        signal: AbortSignal.timeout(600000),
      });

      const result = await response.json();
      logger.info('[Weixin Python] Response:', { ...result, screenshot_base64: result.screenshot_base64 ? '[截图已省略]' : undefined });

      // 使用通用的 AI 辅助处理方法
      return await this.aiProcessPythonPublishResult(result, undefined, onProgress);
    } catch (error) {
      logger.error('[Weixin Python] Publish failed:', error);
      throw error;
    }
  }
  
  async publishVideo(
    cookies: string,
    params: PublishParams,
    onProgress?: (progress: number, message: string) => void,
    onCaptchaRequired?: (captchaInfo: { taskId: string; type: 'sms' | 'image'; phone?: string; imageBase64?: string }) => Promise<string>,
    options?: { headless?: boolean }
  ): Promise<PublishResult> {
    // 只使用 Python 服务发布
    const pythonAvailable = await this.checkPythonServiceAvailable();
    if (!pythonAvailable) {
      logger.error('[Weixin] Python service not available');
      return {
        success: false,
        errorMessage: 'Python 发布服务不可用，请确保 Python 服务已启动',
      };
    }

    logger.info('[Weixin] Using Python service for publishing');
    try {
      const result = await this.publishVideoViaPython(cookies, params, onProgress);
      
      // 检查是否需要验证码
      if (!result.success && result.errorMessage?.includes('验证码')) {
        logger.info('[Weixin] Python detected captcha, need headful browser');
        return {
          success: false,
          errorMessage: `CAPTCHA_REQUIRED:${result.errorMessage}`,
        };
      }
      
      return result;
    } catch (pythonError) {
      logger.error('[Weixin] Python publish failed:', pythonError);
      return {
        success: false,
        errorMessage: pythonError instanceof Error ? pythonError.message : '发布失败',
      };
    }

    /* ========== Playwright 方式已注释，只使用 Python API ==========
    const useHeadless = options?.headless ?? true;

    try {
      logger.info('[Weixin Publish] Initializing browser...');
      await this.initBrowser({ headless: useHeadless });
      
      if (!this.page) {
        throw new Error('浏览器初始化失败，page 为 null');
      }
      
      logger.info('[Weixin Publish] Setting cookies...');
      await this.setCookies(cookies);

      // 再次检查 page 状态
      if (!this.page) throw new Error('Page not initialized after setCookies');

      onProgress?.(5, '正在打开上传页面...');

      await this.page.goto(this.publishUrl, {
        waitUntil: 'domcontentloaded',
        timeout: 60000,
      });

      await this.page.waitForTimeout(3000);

      // 先关闭可能存在的弹窗
      await this.closeModalDialogs();

      // 检查是否需要登录
      const currentUrl = this.page.url();
      if (currentUrl.includes('login')) {
        await this.closeBrowser();
        return {
          success: false,
          errorMessage: '账号登录已过期，请重新登录',
        };
      }

      // 再次关闭可能的弹窗
      await this.closeModalDialogs();

      // 检查是否在发布页面，如果不在则尝试点击"发表视频"按钮
      const pageUrl = this.page.url();
      if (!pageUrl.includes('post/create')) {
        logger.info('[Weixin Publish] Not on publish page, looking for "发表视频" button...');
        onProgress?.(8, '正在进入发布页面...');
        
        // 使用AI寻找发表视频按钮
        try {
          const screenshot = await this.screenshotBase64();
          const guide = await aiService.getPageOperationGuide(screenshot, 'weixin_video', '找到"发表视频"按钮并点击进入视频发布页面');
          logger.info(`[Weixin Publish] AI guide for publish button:`, guide);
          
          if (guide.hasAction && guide.targetSelector) {
            await this.page.click(guide.targetSelector, { timeout: 5000 });
            await this.page.waitForTimeout(3000);
          }
        } catch (e) {
          logger.warn(`[Weixin Publish] AI could not find publish button: ${e}`);
        }
        
        // 尝试常见的发表视频按钮选择器
        const publishBtnSelectors = [
          'button:has-text("发表视频")',
          'a:has-text("发表视频")',
          '[class*="publish"]:has-text("发表")',
          '[class*="create"]:has-text("发表")',
          '.post-video-btn',
        ];
        
        for (const selector of publishBtnSelectors) {
          try {
            const btn = this.page.locator(selector).first();
            if (await btn.count() > 0 && await btn.isVisible()) {
              logger.info(`[Weixin Publish] Found publish button: ${selector}`);
              await btn.click({ timeout: 5000 });
              await this.page.waitForTimeout(3000);
              break;
            }
          } catch (e) {
            // 继续尝试下一个选择器
          }
        }
        
        // 关闭可能弹出的弹窗
        await this.closeModalDialogs();
      }

      onProgress?.(10, '正在上传视频...');

      // 上传视频 - 优先使用 AI 截图分析找到上传入口
      let uploadTriggered = false;

      // 方法1: AI 截图分析找到上传入口
      logger.info('[Weixin Publish] Using AI to find upload entry...');
      try {
        const screenshot = await this.screenshotBase64();
        const guide = await aiService.getPageOperationGuide(screenshot, 'weixin_video', '找到视频上传入口并点击上传按钮');
        logger.info(`[Weixin Publish] AI analysis result:`, guide);

        if (guide.hasAction && guide.targetSelector) {
          logger.info(`[Weixin Publish] AI suggested selector: ${guide.targetSelector}`);
          try {
            const [fileChooser] = await Promise.all([
              this.page.waitForEvent('filechooser', { timeout: 10000 }),
              this.page.click(guide.targetSelector),
            ]);
            await fileChooser.setFiles(params.videoPath);
            uploadTriggered = true;
            logger.info('[Weixin Publish] Upload triggered via AI selector');
          } catch (e) {
            logger.warn(`[Weixin Publish] AI selector click failed: ${e}`);
          }
        }
      } catch (e) {
        logger.warn(`[Weixin Publish] AI analysis failed: ${e}`);
      }

      // 方法2: 尝试点击常见的上传区域触发 file chooser
      if (!uploadTriggered) {
        logger.info('[Weixin Publish] Trying common upload selectors...');
        const uploadSelectors = [
          // 微信视频号发布页面 - 带"+"号的上传区域
          '[class*="add-media"]',
          '[class*="add-video"]',
          '[class*="media-add"]',
          '[class*="video-add"]',
          '[class*="plus"]',
          '[class*="add-btn"]',
          '[class*="add-icon"]',
          // 视频封面/媒体区域
          '[class*="video-cover"]',
          '[class*="media-cover"]',
          '[class*="cover-upload"]',
          '[class*="media-upload"]',
          '[class*="post-media"]',
          // 通用上传区域
          '[class*="upload-area"]',
          '[class*="upload-btn"]',
          '[class*="upload-video"]',
          '[class*="video-upload"]',
          '[class*="upload-content"]',
          '[class*="upload-zone"]',
          '[class*="upload-wrap"]',
          '[class*="uploader"]',
          // 拖拽区域
          '[class*="drag"]',
          '[class*="drop"]',
          // 匹配上传提示文字
          'div:has-text("上传时长")',
          'div:has-text("点击上传")',
          'div:has-text("拖拽上传")',
          'div:has-text("MP4")',
          // 带虚线边框的容器
          '[style*="dashed"]',
          '[class*="dashed"]',
          // 微信视频号特有选择器
          '[class*="post-cover"]',
          '.weui-desktop-upload__area',
          '[class*="finder-upload"]',
          '[class*="finder-post"]',
          // 通用触发器
          '.upload-trigger',
          '.video-uploader',
          '.add-video-btn',
        ];
        
        for (const selector of uploadSelectors) {
          if (uploadTriggered) break;
          try {
            const element = this.page.locator(selector).first();
            if (await element.count() > 0 && await element.isVisible()) {
              logger.info(`[Weixin Publish] Trying selector: ${selector}`);
              const [fileChooser] = await Promise.all([
                this.page.waitForEvent('filechooser', { timeout: 5000 }),
                element.click(),
              ]);
              await fileChooser.setFiles(params.videoPath);
              uploadTriggered = true;
              logger.info(`[Weixin Publish] Upload triggered via selector: ${selector}`);
            }
          } catch (e) {
            // 继续尝试下一个选择器
          }
        }
      }

      // 方法3: 直接设置 file input
      if (!uploadTriggered) {
        logger.info('[Weixin Publish] Trying file input method...');
        const fileInputs = await this.page.$$('input[type="file"]');
        logger.info(`[Weixin Publish] Found ${fileInputs.length} file inputs`);
        for (const fileInput of fileInputs) {
          try {
            const accept = await fileInput.getAttribute('accept');
            if (!accept || accept.includes('video') || accept.includes('*')) {
              await fileInput.setInputFiles(params.videoPath);
              uploadTriggered = true;
              logger.info('[Weixin Publish] Upload triggered via file input');
              break;
            }
          } catch (e) {
            logger.warn(`[Weixin Publish] File input method failed: ${e}`);
          }
        }
      }

      // 方法4: 如果AI给出了坐标，尝试基于坐标点击
      if (!uploadTriggered) {
        logger.info('[Weixin Publish] Trying AI position-based click...');
        try {
          const screenshot = await this.screenshotBase64();
          const guide = await aiService.getPageOperationGuide(screenshot, 'weixin_video', '请找到页面上的视频上传区域或"发表视频"按钮，返回该元素的中心坐标');
          logger.info(`[Weixin Publish] AI position analysis:`, guide);
          
          if (guide.hasAction && guide.targetPosition) {
            const { x, y } = guide.targetPosition;
            logger.info(`[Weixin Publish] Clicking at position: ${x}, ${y}`);
            
            // 先尝试普通点击（可能是"发表视频"按钮）
            await this.page.mouse.click(x, y);
            await this.page.waitForTimeout(2000);
            
            // 检查是否触发了文件选择器或跳转到了发布页
            const newUrl = this.page.url();
            if (newUrl.includes('post/create')) {
              logger.info('[Weixin Publish] Navigated to publish page, retrying upload...');
              // 重新尝试上传
              const uploadArea = this.page.locator('[class*="upload"], [class*="drag"]').first();
              if (await uploadArea.count() > 0) {
                const [fileChooser] = await Promise.all([
                  this.page.waitForEvent('filechooser', { timeout: 10000 }),
                  uploadArea.click(),
                ]);
                await fileChooser.setFiles(params.videoPath);
                uploadTriggered = true;
                logger.info('[Weixin Publish] Upload triggered after navigation');
              }
            }
          }
        } catch (e) {
          logger.warn(`[Weixin Publish] Position-based click failed: ${e}`);
        }
      }

      // 方法5: 点击页面左侧区域（微信视频号发布页面的上传区域在左侧）
      if (!uploadTriggered) {
        logger.info('[Weixin Publish] Trying left area click (upload area is usually on the left)...');
        try {
          const viewport = this.page.viewportSize();
          if (viewport) {
            // 微信视频号发布页面的上传区域在页面左侧中央
            // 根据截图布局，大约在 x=400-550, y=250-400 的区域
            const clickPositions = [
              { x: viewport.width * 0.35, y: viewport.height * 0.35 }, // 左侧偏上
              { x: viewport.width * 0.35, y: viewport.height * 0.4 },  // 左侧中央
              { x: 450, y: 300 }, // 固定位置尝试
              { x: 540, y: 350 }, // 固定位置尝试
            ];
            
            for (const pos of clickPositions) {
              if (uploadTriggered) break;
              try {
                logger.info(`[Weixin Publish] Trying click at: ${pos.x}, ${pos.y}`);
                const [fileChooser] = await Promise.all([
                  this.page.waitForEvent('filechooser', { timeout: 5000 }),
                  this.page.mouse.click(pos.x, pos.y),
                ]);
                await fileChooser.setFiles(params.videoPath);
                uploadTriggered = true;
                logger.info(`[Weixin Publish] Upload triggered via position click: ${pos.x}, ${pos.y}`);
              } catch (e) {
                // 继续尝试下一个位置
              }
            }
          }
        } catch (e) {
          logger.warn(`[Weixin Publish] Left area click failed: ${e}`);
        }
      }

      if (!uploadTriggered) {
        // 截图调试
        try {
          if (this.page) {
            const screenshotPath = `uploads/debug/weixin_no_upload_${Date.now()}.png`;
            await this.page.screenshot({ path: screenshotPath, fullPage: true });
            logger.info(`[Weixin Publish] Screenshot saved: ${screenshotPath}`);
          }
        } catch {}
        throw new Error('未找到上传入口');
      }

      onProgress?.(20, '视频上传中...');

      // 等待上传完成
      const maxWaitTime = 300000; // 5分钟
      const startTime = Date.now();
      let lastAiCheckTime = 0;
      const aiCheckInterval = 10000; // 每10秒使用AI检测一次

      while (Date.now() - startTime < maxWaitTime) {
        // 检查发布按钮是否可用
        try {
          const buttonClass = await this.page.getByRole('button', { name: '发表' }).getAttribute('class');
          if (buttonClass && !buttonClass.includes('disabled')) {
            logger.info('[Weixin Publish] Upload completed, publish button enabled');
            break;
          }
        } catch {
          // 继续等待
        }

        // 检查上传进度（通过DOM）
        let progressDetected = false;
        const progressText = await this.page.locator('[class*="progress"]').first().textContent().catch(() => '');
        if (progressText) {
          const match = progressText.match(/(\d+)%/);
          if (match) {
            const progress = parseInt(match[1]);
            onProgress?.(20 + Math.floor(progress * 0.4), `视频上传中: ${progress}%`);
            progressDetected = true;
            if (progress >= 100) {
              logger.info('[Weixin Publish] Upload progress reached 100%');
              break;
            }
          }
        }

        // 使用AI检测上传进度（每隔一段时间检测一次）
        if (!progressDetected && Date.now() - lastAiCheckTime > aiCheckInterval) {
          lastAiCheckTime = Date.now();
          try {
            const screenshot = await this.screenshotBase64();
            const uploadStatus = await aiService.analyzeUploadProgress(screenshot, 'weixin_video');
            logger.info(`[Weixin Publish] AI upload status:`, uploadStatus);
            
            if (uploadStatus.isComplete) {
              logger.info('[Weixin Publish] AI detected upload complete');
              break;
            }
            
            if (uploadStatus.isFailed) {
              throw new Error(`视频上传失败: ${uploadStatus.statusDescription}`);
            }
            
            if (uploadStatus.progress !== null) {
              onProgress?.(20 + Math.floor(uploadStatus.progress * 0.4), `视频上传中: ${uploadStatus.progress}%`);
              if (uploadStatus.progress >= 100) {
                logger.info('[Weixin Publish] AI detected progress 100%');
                break;
              }
            }
          } catch (aiError) {
            logger.warn('[Weixin Publish] AI progress check failed:', aiError);
          }
        }

        await this.page.waitForTimeout(3000);
      }

      onProgress?.(60, '正在填写视频信息...');

      // 填写标题和话题
      const editorDiv = this.page.locator('div.input-editor, [contenteditable="true"]').first();
      if (await editorDiv.count() > 0) {
        await editorDiv.click();
        await this.page.keyboard.type(params.title);

        if (params.tags && params.tags.length > 0) {
          await this.page.keyboard.press('Enter');
          for (const tag of params.tags) {
            await this.page.keyboard.type('#' + tag);
            await this.page.keyboard.press('Space');
          }
        }
      }

      onProgress?.(80, '正在发布...');

      // 点击发布
      const publishBtn = this.page.locator('div.form-btns button:has-text("发表"), button:has-text("发表")').first();
      if (await publishBtn.count() > 0) {
        await publishBtn.click();
      } else {
        throw new Error('未找到发布按钮');
      }

      // 等待发布结果
      onProgress?.(90, '等待发布完成...');
      const publishMaxWait = 120000; // 2分钟
      const publishStartTime = Date.now();
      let aiCheckCounter = 0;
      let lastProgressCheckTime = 0;
      const progressCheckInterval = 5000; // 每5秒检测一次发布进度

      while (Date.now() - publishStartTime < publishMaxWait) {
        await this.page.waitForTimeout(3000);
        const newUrl = this.page.url();

        // 检查是否跳转到列表页
        if (newUrl.includes('/post/list')) {
          onProgress?.(100, '发布成功！');
          await this.closeBrowser();
          return {
            success: true,
            videoUrl: newUrl,
          };
        }

        // 检查发布进度条（DOM方式）
        const publishProgressText = await this.page.locator('[class*="progress"], [class*="loading"]').first().textContent().catch(() => '');
        if (publishProgressText) {
          const match = publishProgressText.match(/(\d+)%/);
          if (match) {
            const progress = parseInt(match[1]);
            onProgress?.(90 + Math.floor(progress * 0.1), `发布中: ${progress}%`);
            logger.info(`[Weixin Publish] Publish progress: ${progress}%`);
          }
        }

        // AI检测发布进度（定期检测）
        if (Date.now() - lastProgressCheckTime > progressCheckInterval) {
          lastProgressCheckTime = Date.now();
          try {
            const screenshot = await this.screenshotBase64();
            const publishStatus = await aiService.analyzePublishProgress(screenshot, 'weixin_video');
            logger.info(`[Weixin Publish] AI publish status:`, publishStatus);
            
            if (publishStatus.isComplete) {
              logger.info('[Weixin Publish] AI detected publish complete');
              onProgress?.(100, '发布成功！');
              await this.closeBrowser();
              return { success: true, videoUrl: this.page.url() };
            }
            
            if (publishStatus.isFailed) {
              throw new Error(`发布失败: ${publishStatus.statusDescription}`);
            }
            
            if (publishStatus.progress !== null) {
              onProgress?.(90 + Math.floor(publishStatus.progress * 0.1), `发布中: ${publishStatus.progress}%`);
            }
            
            if (publishStatus.isPublishing) {
              logger.info(`[Weixin Publish] Still publishing: ${publishStatus.statusDescription}`);
            }
          } catch (aiError) {
            logger.warn('[Weixin Publish] AI publish progress check failed:', aiError);
          }
        }

        // 检查错误提示
        const errorHint = await this.page.locator('[class*="error"], [class*="fail"]').first().textContent().catch(() => '');
        if (errorHint && (errorHint.includes('失败') || errorHint.includes('错误'))) {
          throw new Error(`发布失败: ${errorHint}`);
        }

        // AI 辅助检测状态（每 3 次循环）
        aiCheckCounter++;
        if (aiCheckCounter >= 3) {
          aiCheckCounter = 0;
          const aiStatus = await this.aiAnalyzePublishStatus();
          if (aiStatus) {
            logger.info(`[Weixin Publish] AI status: ${aiStatus.status}, confidence: ${aiStatus.confidence}%`);

            if (aiStatus.status === 'success' && aiStatus.confidence >= 70) {
              onProgress?.(100, '发布成功！');
              await this.closeBrowser();
              return { success: true, videoUrl: this.page.url() };
            }

            if (aiStatus.status === 'failed' && aiStatus.confidence >= 70) {
              throw new Error(aiStatus.errorMessage || 'AI 检测到发布失败');
            }

            if (aiStatus.status === 'need_captcha' && onCaptchaRequired) {
              const imageBase64 = await this.screenshotBase64();
              try {
                const captchaCode = await onCaptchaRequired({
                  taskId: `weixin_captcha_${Date.now()}`,
                  type: 'image',
                  imageBase64,
                });
                if (captchaCode) {
                  const guide = await this.aiGetPublishOperationGuide('需要输入验证码');
                  if (guide?.hasAction && guide.targetSelector) {
                    await this.page.fill(guide.targetSelector, captchaCode);
                  }
                }
              } catch {
                logger.error('[Weixin Publish] Captcha handling failed');
              }
            }

            if (aiStatus.status === 'need_action' && aiStatus.nextAction) {
              const guide = await this.aiGetPublishOperationGuide(aiStatus.pageDescription);
              if (guide?.hasAction) {
                await this.aiExecuteOperation(guide);
              }
            }
          }
        }
      }

      // 超时，AI 最终检查
      const finalAiStatus = await this.aiAnalyzePublishStatus();
      if (finalAiStatus?.status === 'success') {
        onProgress?.(100, '发布成功！');
        await this.closeBrowser();
        return { success: true, videoUrl: this.page.url() };
      }

      throw new Error('发布超时，请手动检查是否发布成功');

    } catch (error) {
      logger.error('Weixin publishVideo error:', error);
      await this.closeBrowser();
      return {
        success: false,
        errorMessage: error instanceof Error ? error.message : '发布失败',
      };
    }
    ========== Playwright 方式已注释结束 ========== */
  }
  
  /**
   * 通过 Python API 获取评论
   */
  private async getCommentsViaPython(cookies: string, videoId: string): Promise<CommentData[]> {
    logger.info('[Weixin] Getting comments via Python API...');
    
    const response = await fetch(`${PYTHON_PUBLISH_SERVICE_URL}/comments`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        platform: 'weixin',
        cookie: cookies,
        work_id: videoId,
      }),
    });
    
    if (!response.ok) {
      throw new Error(`Python API returned ${response.status}`);
    }
    
    const result = await response.json();
    
    if (!result.success) {
      throw new Error(result.error || 'Failed to get comments');
    }
    
    // 转换数据格式
    return (result.comments || []).map((comment: {
      comment_id: string;
      author_id: string;
      author_name: string;
      author_avatar: string;
      content: string;
      like_count: number;
      create_time: string;
      reply_count: number;
    }) => ({
      commentId: comment.comment_id,
      authorId: comment.author_id,
      authorName: comment.author_name,
      authorAvatar: comment.author_avatar,
      content: comment.content,
      likeCount: comment.like_count,
      commentTime: comment.create_time,
      replyCount: comment.reply_count,
    }));
  }

  async getComments(cookies: string, videoId: string): Promise<CommentData[]> {
    // 优先尝试使用 Python API
    const pythonAvailable = await this.checkPythonServiceAvailable();
    if (pythonAvailable) {
      logger.info('[Weixin] Python service available, using Python API for comments');
      try {
        return await this.getCommentsViaPython(cookies, videoId);
      } catch (pythonError) {
        logger.warn('[Weixin] Python API getComments failed:', pythonError);
      }
    }
    
    logger.warn('Weixin getComments - Python API not available');
    return [];
  }
  
  async replyComment(cookies: string, videoId: string, commentId: string, content: string): Promise<boolean> {
    logger.warn('Weixin replyComment not implemented');
    return false;
  }
  
  async getAnalytics(cookies: string, dateRange?: DateRange): Promise<AnalyticsData> {
    logger.warn('Weixin getAnalytics not implemented');
    return {
      totalViews: 0,
      totalLikes: 0,
      totalComments: 0,
      totalShares: 0,
      periodViews: [],
    };
  }
}
