/// <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());

/**
 * B站平台适配器
 */
export class BilibiliAdapter extends BasePlatformAdapter {
  readonly platform: PlatformType = 'bilibili';
  readonly loginUrl = 'https://member.bilibili.com/';
  readonly publishUrl = 'https://member.bilibili.com/platform/upload/video/frame';
  
  protected getCookieDomain(): string {
    return '.bilibili.com';
  }
  
  async getQRCode(): Promise<QRCodeInfo> {
    try {
      await this.initBrowser();
      
      if (!this.page) throw new Error('Page not initialized');
      
      await this.page.goto('https://passport.bilibili.com/login');
      await this.waitForSelector('.login-scan-img img', 30000);
      
      const qrcodeImg = await this.page.$('.login-scan-img img');
      const qrcodeUrl = await qrcodeImg?.getAttribute('src');
      
      if (!qrcodeUrl) {
        throw new Error('Failed to get QR code');
      }
      
      return {
        qrcodeUrl,
        qrcodeKey: `bilibili_${Date.now()}`,
        expireTime: Date.now() + 180000,
      };
    } catch (error) {
      logger.error('Bilibili getQRCode error:', error);
      throw error;
    }
  }
  
  async checkQRCodeStatus(qrcodeKey: string): Promise<LoginStatusResult> {
    try {
      if (!this.page) {
        return { status: 'expired', message: '二维码已过期' };
      }
      
      const currentUrl = this.page.url();
      
      if (currentUrl.includes('member.bilibili.com')) {
        const cookies = await this.getCookies();
        await this.closeBrowser();
        return { status: 'success', message: '登录成功', cookies };
      }
      
      return { status: 'waiting', message: '等待扫码' };
    } catch (error) {
      logger.error('Bilibili 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('https://member.bilibili.com/platform/home');
      await this.page.waitForLoadState('networkidle');
      
      const avatar = await this.page.$('.user-avatar');
      await this.closeBrowser();
      
      return !!avatar;
    } catch (error) {
      logger.error('Bilibili checkLoginStatus error:', error);
      await this.closeBrowser();
      return false;
    }
  }
  
  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://member.bilibili.com/platform/home');
      await this.page.waitForLoadState('networkidle');
      
      const accountName = await this.page.$eval('.user-name', el => el.textContent?.trim() || '');
      const avatarUrl = await this.page.$eval('.user-avatar img', el => el.getAttribute('src') || '');
      
      await this.closeBrowser();
      
      return {
        accountId: '',
        accountName,
        avatarUrl,
        fansCount: 0,
        worksCount: 0,
      };
    } catch (error) {
      logger.error('Bilibili getAccountInfo error:', error);
      await this.closeBrowser();
      throw error;
    }
  }
  
  /**
   * 检查 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('bilibili');
      }
      return false;
    } catch {
      return false;
    }
  }

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

    try {
      // 准备 cookie 字符串
      let cookieStr = cookies;
      try {
        const cookieArray = JSON.parse(cookies);
        if (Array.isArray(cookieArray)) {
          cookieStr = cookieArray.map((c: { name: string; value: string }) => `${c.name}=${c.value}`).join('; ');
        }
      } catch {
        // 已经是字符串格式
      }

      // 将相对路径转换为绝对路径
      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: 'bilibili',
          cookie: cookieStr,
          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,
          return_screenshot: true,
        }),
        signal: AbortSignal.timeout(600000), // 10分钟超时
      });

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

      // 使用通用的 AI 辅助处理方法
      return await this.aiProcessPythonPublishResult(result, undefined, onProgress);
    } catch (error) {
      logger.error('[Bilibili 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('[Bilibili] Python service not available');
      return {
        success: false,
        errorMessage: 'Python 发布服务不可用，请确保 Python 服务已启动',
      };
    }

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

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

    try {
      await this.initBrowser({ headless: useHeadless });
      await this.setCookies(cookies);

      if (!this.page) throw new Error('Page not initialized');

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

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

      await this.page.waitForTimeout(3000);

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

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

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

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

        if (guide.hasAction && guide.targetSelector) {
          logger.info(`[Bilibili 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('[Bilibili Publish] Upload triggered via AI selector');
          } catch (e) {
            logger.warn(`[Bilibili Publish] AI selector click failed: ${e}`);
          }
        }
      } catch (e) {
        logger.warn(`[Bilibili Publish] AI analysis failed: ${e}`);
      }

      // 方法2: 尝试点击常见的上传区域触发 file chooser
      if (!uploadTriggered) {
        logger.info('[Bilibili Publish] Trying common upload selectors...');
        const uploadSelectors = [
          // B站常见上传区域选择器
          '[class*="upload-area"]',
          '[class*="upload-btn"]',
          '[class*="bcc-upload"]',
          '[class*="video-upload"]',
          '[class*="upload-container"]',
          '.upload-trigger',
          '.video-uploader',
          'div[class*="uploader"]',
          'button:has-text("上传")',
          'div:has-text("上传视频"):not(:has(div))',
          'span:has-text("点击上传")',
          '[class*="upload-select"]',
          '.bili-upload',
        ];
        
        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(`[Bilibili 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(`[Bilibili Publish] Upload triggered via selector: ${selector}`);
            }
          } catch (e) {
            // 继续尝试下一个选择器
          }
        }
      }

      // 方法3: 直接设置 file input
      if (!uploadTriggered) {
        logger.info('[Bilibili Publish] Trying file input method...');
        const fileInputs = await this.page.$$('input[type="file"]');
        logger.info(`[Bilibili 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('[Bilibili Publish] Upload triggered via file input');
              break;
            }
          } catch (e) {
            logger.warn(`[Bilibili Publish] File input method failed: ${e}`);
          }
        }
      }

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

      // 等待上传完成
      onProgress?.(20, '视频上传中...');
      const maxWaitTime = 300000; // 5分钟
      const startTime = Date.now();

      while (Date.now() - startTime < maxWaitTime) {
        // 检查上传进度
        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}%`);
          }
        }

        // 检查上传完成
        const uploadSuccess = await this.page.locator('.upload-success, [class*="success"], [class*="complete"]').count();
        if (uploadSuccess > 0) {
          logger.info('[Bilibili Publish] Video upload completed');
          break;
        }

        await this.page.waitForTimeout(2000);
      }

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

      // 填写标题
      const titleInput = this.page.locator('.video-title input, input[placeholder*="标题"]').first();
      if (await titleInput.count() > 0) {
        await titleInput.fill(params.title);
      }

      // 填写简介
      if (params.description) {
        const descInput = this.page.locator('textarea[placeholder*="简介"], .desc-input textarea').first();
        if (await descInput.count() > 0) {
          await descInput.fill(params.description);
        }
      }

      // 选择分区
      try {
        const typeBtn = this.page.locator('.type-btn, [class*="select-type"]').first();
        if (await typeBtn.count() > 0) {
          await typeBtn.click();
          await this.page.waitForTimeout(500);
          // 默认选择生活区
          const lifeCategory = this.page.locator('[data-tid="160"], :has-text("生活")').first();
          if (await lifeCategory.count() > 0) {
            await lifeCategory.click();
          }
        }
      } catch {
        logger.warn('[Bilibili Publish] Failed to select category');
      }

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

      // 点击发布
      const submitBtn = this.page.locator('.submit-add, button:has-text("投稿"), [class*="submit"]').first();
      if (await submitBtn.count() > 0) {
        await submitBtn.click();
      } else {
        throw new Error('未找到发布按钮');
      }

      // 等待发布结果
      onProgress?.(90, '等待发布完成...');
      const publishMaxWait = 120000; // 2分钟
      const publishStartTime = Date.now();
      let aiCheckCounter = 0;

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

        // 检查成功提示
        const successHint = await this.page.locator('.success-hint, [class*="success"]:has-text("成功")').count();
        if (successHint > 0) {
          onProgress?.(100, '发布成功！');
          await this.closeBrowser();
          return {
            success: true,
            videoUrl: this.page.url(),
          };
        }

        // 检查错误提示
        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(`[Bilibili 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: `bilibili_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('[Bilibili 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('Bilibili publishVideo error:', error);
      await this.closeBrowser();
      return {
        success: false,
        errorMessage: error instanceof Error ? error.message : '发布失败',
      };
    }
    ========== Playwright 方式已注释结束 ========== */
  }
  
  async getComments(cookies: string, videoId: string): Promise<CommentData[]> {
    logger.info(`Bilibili getComments for video ${videoId}`);
    return [];
  }
  
  async replyComment(cookies: string, commentId: string, content: string): Promise<boolean> {
    logger.info(`Bilibili replyComment ${commentId}: ${content}`);
    return true;
  }
  
  async getAnalytics(cookies: string, dateRange: DateRange): Promise<AnalyticsData> {
    return {
      fansCount: 0,
      fansIncrease: 0,
      viewsCount: 0,
      likesCount: 0,
      commentsCount: 0,
      sharesCount: 0,
    };
  }
}
