import { Request, Response } from 'express';
import { FingerprintEngine } from '../../core/ai/FingerprintEngine';
import { isValidProductStatusTransition } from '../../core/guards/state-transition.guard';
import { PipelineEngine } from '../../core/pipeline/PipelineEngine';
import { StepStatus } from '../../core/pipeline/PipelineTypes';
import { AIService } from '../../services/ai/AIService';
import { AuditService } from '../../services/utils/AuditService';
import { CompetitorPulseService } from '../../services/core/CompetitorPulseService';
import { ConfigService } from '../../services/utils/ConfigService';
import { CrawlerService } from '../../services/core/CrawlerService';
import { DynamicPricingService } from '../../services/core/DynamicPricingService';
import { MultiPlatformProductService } from '../../services/product/MultiPlatformProductService';
import { ProductCollectionService } from '../../services/product/ProductCollectionService';
import { ProductListingService } from '../../services/product/ProductListingService';
import { ProductService } from '../../services/product/ProductService';
import { SupplierInquiryService } from '../../services/supplier/SupplierInquiryService';
import { SupplyChainService } from '../../services/integration/SupplyChainService';
import { CrawlerWorker } from '../../workers/CrawlerWorker';
import { logger } from '../../utils/logger';

declare module 'express' {
  interface Request {
    traceContext?: {
      tenantId: string;
      shopId: string;
      taskId: string;
      traceId: string;
      userId: string;
      roleCode: string;
      businessType: 'TOC' | 'TOB';
    };
  }
}


export class ProductController {
  /**
   * [BIZ_MKT_30] 触发动态调价
   */
  static async triggerDynamicPricing(req: Request, res: Response) {
    const { id } = req.params;
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, shopId } = traceContext;

    try {
      // 使用 generatePricingDecision 替代 applyDynamicPricing
      const result = await DynamicPricingService.generatePricingDecision(tenantId, shopId, id as string);
      res.json({ success: true, data: result });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }
  /**
   * [CORE_AUTO_01] 启动自治上架流水线
   */
  static async startAutonomousListing(req: Request, res: Response) {
    const { url, targetPlatforms } = req.body;
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, shopId, traceId, userId } = traceContext;

    try {
      const instanceId = await PipelineEngine.start({
        id: 'IAT-LISTING-FLOW',
        name: 'Autonomous Listing Flow',
        steps: [
          { id: 'crawl', type: 'CRAWL', config: { url }, status: StepStatus.PENDING },
          { id: 'optimize', type: 'AI_OPTIMIZE', config: {}, status: StepStatus.PENDING, dependsOn: ['crawl'] },
          { id: 'publish', type: 'MULTI_PUBLISH', config: { platforms: targetPlatforms }, status: StepStatus.PENDING, dependsOn: ['optimize'] }
        ]
      }, {
        tenantId,
        shopId: shopId || '',
        traceId,
        userId,
        variables: { url, targetPlatforms }
      });

      res.json({ success: true, data: { instanceId } });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [CORE_WORK_01] 异步采集接口
   */
  static async collectAsync(req: Request, res: Response) {
    const { url, sandbox } = req.body;
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, shopId, taskId, traceId, userId } = traceContext;

    try {
      const job = await CrawlerWorker.submit({
        url,
        sandbox: sandbox === true,
        traceContext
      });

      await AuditService.log({
        tenantId,
        shopId,
        taskId,
        traceId,
        userId,
        module: 'SYNC',
        action: 'CRAWLER_ASYNC_SUBMIT',
        resourceType: 'product',
        resourceId: url,
        afterSnapshot: { jobId: job.taskId, url },
        result: 'success',
        source: 'console'
      });

      res.json({ success: true, data: { jobId: job.taskId } });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  static async getAll(req: Request, res: Response) {
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId } = traceContext;
    try {
      const { platform, status } = req.query;
      const products = await ProductService.getAll(tenantId, {
        platform: platform as string,
        status: status as string,
      });
      res.json({ success: true, data: products });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [UX_REVIEW_01] 审核商品
   */
  static async approve(req: Request, res: Response) {
    const { id } = req.params;
    const { decision, reason } = req.body; // decision: 'APPROVE' | 'REJECT'
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, userId, traceId } = traceContext;

    try {
      const status = decision === 'APPROVE' ? 'APPROVED' : 'REJECTED';
      await ProductService.update(tenantId, Number(id), { status });

      await AuditService.log({
        tenantId,
        userId,
        traceId,
        module: 'PRODUCT',
        action: 'REVIEW_PRODUCT',
        resourceType: 'product',
        resourceId: id as string,
        metadata: { decision, reason },
        result: 'success',
        source: 'console'
      });

      res.json({ success: true, message: `Product ${decision.toLowerCase()}d successfully` });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  static async getById(req: Request, res: Response) {
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId } = traceContext;
    try {
      const product = await ProductService.getById(tenantId, Number(req.params.id));
      if (!product) return res.status(404).json({ success: false, error: 'Product not found' });
      res.json({ success: true, data: product });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  static async create(req: Request, res: Response) {
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, shopId, taskId, traceId, userId } = traceContext;
    try {
      const id = await ProductService.create(tenantId, req.body);

      await AuditService.log({
        tenantId,
        shopId,
        taskId,
        traceId,
        userId,
        module: 'PRODUCT',
        action: 'CREATE_PRODUCT',
        resourceType: 'product',
        resourceId: String(id),
        afterSnapshot: req.body,
        result: 'success',
        source: 'console'
      });

      res.status(201).json({ success: true, data: { id } });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  static async update(req: Request, res: Response) {
    const id = Number(req.params.id);
    const updateData = req.body;
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, shopId, taskId, traceId, userId, roleCode } = traceContext;

    try {
      const beforeSnapshot = await ProductService.getById(tenantId, id);
      if (!beforeSnapshot) {
        return res.status(404).json({ success: false, error: 'Product not found' });
      }

      if (updateData.status) {
        const previousStatus = String(beforeSnapshot.status || 'DRAFTED');
        const nextStatus = String(updateData.status);
        const validTransition = isValidProductStatusTransition(previousStatus, nextStatus);
        if (!validTransition) {
          await AuditService.log({
            tenantId,
            shopId,
            taskId,
            traceId,
            userId,
            roleCode,
            module: 'PRODUCT',
            action: 'INVALID_STATUS_TRANSITION',
            resourceType: 'product',
            resourceId: String(id),
            beforeSnapshot: { status: previousStatus },
            afterSnapshot: { status: nextStatus },
            result: 'failed',
            errorCode: 'INVALID_STATUS_TRANSITION',
            errorMessage: `Invalid status transition: ${previousStatus} -> ${nextStatus}`,
            source: 'console',
          });
          return res.status(400).json({
            success: false,
            error: `Invalid status transition: ${previousStatus} -> ${nextStatus}`,
          });
        }
      }

      await ProductService.update(tenantId, id, updateData);

      const afterSnapshot = await ProductService.getById(tenantId, id);
      await AuditService.logDiff({
        tenantId,
        shopId,
        taskId,
        traceId,
        userId,
        module: 'PRODUCT',
        action: 'UPDATE_PRODUCT',
        resourceType: 'product',
        resourceId: String(id),
        beforeSnapshot,
        afterSnapshot,
        source: 'console'
      });

      res.json({ success: true, data: afterSnapshot });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  static async delete(req: Request, res: Response) {
    const id = Number(req.params.id);
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, shopId, taskId, traceId, userId } = traceContext;
    try {
      const beforeSnapshot = await ProductService.getById(tenantId, id);
      if (!beforeSnapshot) return res.status(404).json({ success: false, error: 'Product not found' });

      await ProductService.delete(tenantId, id);

      await AuditService.log({
        tenantId,
        shopId,
        taskId,
        traceId,
        userId,
        module: 'PRODUCT',
        action: 'DELETE_PRODUCT',
        resourceType: 'product',
        resourceId: String(id),
        beforeSnapshot,
        result: 'success',
        source: 'console'
      });

      res.json({ success: true });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [CORE_AI_15] 采集、优化并生成复合指纹
   */
  static async collectAndOptimize(req: Request, res: Response) {
    const { url, sandbox: forceSandbox } = req.query;
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, traceId, userId } = traceContext;

    try {
      const configMultiModal = await ConfigService.getConfig('ENABLE_MULTI_MODAL_AI');
      const configSandbox = await ConfigService.getConfig('ENABLE_SANDBOX_CRAWLER');

      const isMultiModalEnabled = configMultiModal?.value === 'true';
      const isSandboxEnabled = forceSandbox === 'true' || configSandbox?.value === 'true';

      const crawler = new CrawlerService();
      let productData = await crawler.crawl(url as string, String(isSandboxEnabled));

      if (isMultiModalEnabled) {
        const optimized = await AIService.optimizeProduct(productData.title || '', productData.attributes || {});
        productData = { ...productData, title: optimized };
      }

      // 生成复合指纹
      const fingerprint = await FingerprintEngine.generateCompositeFingerprint({
        title: productData.title || '',
        description: productData.description || '',
        mainImage: productData.mainImage || ''
      });

      const id = await ProductService.create(tenantId, { 
        ...productData, 
        phash: fingerprint.phash,
        semantic_hash: fingerprint.semanticHash,
        vector_embedding: JSON.stringify(fingerprint.vectorEmbedding)
      });

      res.json({ success: true, data: { id, ...productData, ...fingerprint, sandboxUsed: isSandboxEnabled } });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [BIZ_PROD_12] 商品全自动清洗与本地化 (Washer)
   */
  static async washAndLocalize(req: Request, res: Response) {
    const id = Number(req.params.id);
    const { targetMarket, targetLang } = req.body;
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, shopId, traceId, userId } = traceContext;

    try {
      const result = await ProductService.washAndLocalize(tenantId, id, targetMarket, targetLang);

      await AuditService.log({
        tenantId,
        shopId,
        traceId,
        userId,
        module: 'PRODUCT',
        action: 'PRODUCT_WASH_AND_LOCALIZE',
        resourceType: 'product',
        resourceId: String(id),
        afterSnapshot: result,
        result: 'success',
        source: 'console'
      });

      res.json({ success: true, data: result });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [BIZ_EXT_10] 供应链溯源
   */
  static async traceSource(req: Request, res: Response) {
    const { imageUrl } = req.body;
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId } = traceContext;
    try {
      const sources = await SupplyChainService.traceSourceFactory(tenantId, '', imageUrl);
      res.json({ success: true, data: sources });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [CORE_AI_50] 利润链路分析
   */
  static async analyzeProfit(req: Request, res: Response) {
    const { productId, consumerPrice } = req.body;
    try {
      const analysis = await SupplyChainService.analyzeProfitChain(Number(productId), Number(consumerPrice));
      res.json({ success: true, data: analysis });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [BIZ_EXT_07] 套利机会分析
   */
  static async analyzeArbitrage(req: Request, res: Response) {
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId } = traceContext;
    const { id } = req.params;
    try {
      const result = await ProductService.analyzeProductArbitrage(tenantId, Number(id));
      res.json({ success: true, data: result });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * 获取动态调价建议
   */
  static async getPriceAdvice(req: Request, res: Response) {
    const id = String(req.params.id);
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, shopId, taskId, traceId, userId } = traceContext;
    try {
      // 使用 generatePricingDecision 替代 calculateOptimalPrice
      const advice = await DynamicPricingService.generatePricingDecision(tenantId, shopId, id);

      await AuditService.log({
        tenantId,
        shopId,
        taskId,
        traceId,
        userId,
        module: 'PRODUCT',
        action: 'GET_PRICE_ADVICE',
        resourceType: 'product',
        resourceId: String(id),
        afterSnapshot: advice,
        result: 'success',
        source: 'console'
      });

      res.json({ success: true, data: advice });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * 同行竞态检查
   */
  static async checkPulse(req: Request, res: Response) {
    const id = Number(req.params.id);
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, shopId, taskId, traceId, userId } = traceContext;
    try {
      const result = await CompetitorPulseService.pulseCheck(id);
      
      await AuditService.log({
        tenantId,
        shopId,
        taskId,
        traceId,
        userId,
        module: 'PRODUCT',
        action: 'CHECK_PULSE',
        resourceType: 'product',
        resourceId: String(id),
        afterSnapshot: result,
        result: 'success',
        source: 'console'
      });

      res.json({ success: true, data: result });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * 生成询价单
   */
  static async generateInquiry(req: Request, res: Response) {
    const id = Number(req.params.id);
    const { quantity } = req.body;
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, shopId, taskId, traceId, userId } = traceContext;
    try {
      const product = await ProductService.getById(tenantId, id);
      if (!product) return res.status(404).json({ success: false, error: 'Product not found' });

      const inquiry = await SupplierInquiryService.generateInquiry({
        productTitle: product.title || '',
        attributes: product.attributes || {},
        targetQuantity: quantity || 100,
        platform: product.platform
      });

      await AuditService.log({
        tenantId,
        shopId,
        taskId,
        traceId,
        userId,
        module: 'TRADE',
        action: 'GENERATE_INQUIRY',
        resourceType: 'product',
        resourceId: String(id),
        afterSnapshot: inquiry,
        result: 'success',
        source: 'console'
      });

      res.json({ success: true, data: inquiry });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * 视觉匹配相似产品
   */
  static async findSimilar(req: Request, res: Response) {
    const { imageUrl } = req.query;
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId } = traceContext;
    try {
      if (!imageUrl) {
        return res.status(400).json({ success: false, error: 'imageUrl is required' });
      }

      const fingerprint = await FingerprintEngine.generateCompositeFingerprint({
        title: '',
        description: '',
        mainImage: imageUrl as string
      });

      const similarProducts = await ProductService.findByFingerprint(tenantId, fingerprint);

      res.json({ success: true, data: similarProducts });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [BE-P006] 多平台商品整合接口
   */
  static async createPlatformMapping(req: Request, res: Response) {
    const { masterProductId, masterPlatform, platformMappings } = req.body;
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, shopId, taskId, traceId, userId } = traceContext;

    try {
      const mappings = await MultiPlatformProductService.createMapping(
        tenantId,
        masterProductId,
        masterPlatform,
        platformMappings
      );

      await AuditService.log({
        tenantId,
        shopId,
        taskId,
        traceId,
        userId,
        module: 'PRODUCT',
        action: 'CREATE_PLATFORM_MAPPING',
        resourceType: 'product',
        resourceId: masterProductId,
        afterSnapshot: { mappings },
        result: 'success',
        source: 'console'
      });

      res.status(201).json({ success: true, data: mappings });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [BE-P006] 获取商品的平台映射
   */
  static async getPlatformMappings(req: Request, res: Response) {
    const { productId } = req.params;
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId } = traceContext;

    try {
      const mappings = await MultiPlatformProductService.getMappings(tenantId, productId as string);
      res.json({ success: true, data: mappings });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [BE-P007] 批量商品操作接口
   */
  static async batchOperation(req: Request, res: Response) {
    const { productIds, operation } = req.body;
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, shopId, taskId, traceId, userId } = traceContext;

    try {
      const result = await MultiPlatformProductService.batchOperation(
        tenantId,
        productIds,
        operation
      );

      await AuditService.log({
        tenantId,
        shopId,
        taskId,
        traceId,
        userId,
        module: 'PRODUCT',
        action: 'BATCH_OPERATION',
        resourceType: 'product',
        metadata: { operation, totalItems: result.totalItems, successItems: result.successItems },
        result: result.success ? 'success' : 'failed',
        source: 'console'
      });

      res.json({ success: result.success, data: result });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [BE-P008] 跨平台库存同步接口
   */
  static async syncInventory(req: Request, res: Response) {
    const { productId } = req.params;
    const { quantity, platforms } = req.body;
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, shopId, taskId, traceId, userId } = traceContext;

    try {
      const syncResults = await MultiPlatformProductService.syncInventory(
        tenantId,
        productId as string,
        quantity,
        platforms
      );

      await AuditService.log({
        tenantId,
        shopId,
        taskId,
        traceId,
        userId,
        module: 'PRODUCT',
        action: 'SYNC_INVENTORY',
        resourceType: 'product',
        resourceId: productId as string,
        afterSnapshot: { quantity, syncResults },
        result: 'success',
        source: 'console'
      });

      res.json({ success: true, data: syncResults });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [BE-P008] 获取库存同步状态
   */
  static async getSyncStatus(req: Request, res: Response) {
    const { productId } = req.params;
    const traceContext = req.traceContext;
    
    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId } = traceContext;

    try {
      const mappings = await MultiPlatformProductService.getMappings(tenantId, productId as string);
      const syncStatus = mappings.map((m: any) => ({
        platform: m.platform,
        platformProductId: m.platformProductId,
        status: m.status,
        lastSyncAt: m.lastSyncAt,
        syncError: m.syncError,
      }));
      res.json({ success: true, data: syncStatus });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [BE-P101] 创建数据采集任务
   */
  static async createCollectionTask(req: Request, res: Response) {
    const { platform, sourceUrl, businessType } = req.body;
    const traceContext = req.traceContext;

    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, shopId, traceId, userId } = traceContext;

    try {
      const collectionService = new ProductCollectionService();
      const taskId = await collectionService.createTask(
        tenantId,
        shopId || '',
        businessType as 'TOC' | 'TOB',
        platform,
        sourceUrl,
        traceId
      );

      await AuditService.log({
        tenantId,
        shopId: shopId || '',
        traceId,
        userId,
        module: 'PRODUCT',
        action: 'CREATE_COLLECTION_TASK',
        resourceType: 'collection_task',
        resourceId: taskId,
        afterSnapshot: { platform, sourceUrl, businessType },
        result: 'success',
        source: 'console'
      });

      res.status(201).json({ success: true, data: { taskId } });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [BE-P101] 执行数据采集任务
   */
  static async executeCollectionTask(req: Request, res: Response) {
    const taskId = typeof req.params.taskId === 'string' ? req.params.taskId : '';
    const traceContext = req.traceContext;

    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, userId } = traceContext;

    try {
      const collectionService = new ProductCollectionService();

      // 异步执行采集任务
      collectionService.executeCollection(taskId).catch((error: any) => {
        logger.error(`[ProductController] Collection task failed: ${taskId}`, error);
      });

      await AuditService.log({
        tenantId,
        shopId: '',
        traceId: traceContext.traceId,
        userId,
        module: 'PRODUCT',
        action: 'EXECUTE_COLLECTION_TASK',
        resourceType: 'collection_task',
        resourceId: taskId,
        result: 'success',
        source: 'console'
      });

      res.json({ success: true, data: { taskId, status: 'started' } });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [BE-P101] 获取采集任务列表
   */
  static async getCollectionTasks(req: Request, res: Response) {
    const traceContext = req.traceContext;

    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId } = traceContext;
    const { status, platform, limit = '20', offset = '0' } = req.query;

    try {
      const collectionService = new ProductCollectionService();
      const tasks = await collectionService.getTasks(tenantId, {
        status: status as any,
        platform: platform as string,
        limit: parseInt(limit as string),
        offset: parseInt(offset as string)
      });

      res.json({ success: true, data: tasks });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [BE-P101] 重试失败的采集任务
   */
  static async retryCollectionTask(req: Request, res: Response) {
    const taskId = typeof req.params.taskId === 'string' ? req.params.taskId : '';
    const traceContext = req.traceContext;

    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, userId } = traceContext;

    try {
      const collectionService = new ProductCollectionService();
      await collectionService.retryTask(taskId);

      await AuditService.log({
        tenantId,
        shopId: '',
        traceId: traceContext.traceId,
        userId,
        module: 'PRODUCT',
        action: 'RETRY_COLLECTION_TASK',
        resourceType: 'collection_task',
        resourceId: taskId,
        result: 'success',
        source: 'console'
      });

      res.json({ success: true, data: { taskId, status: 'retrying' } });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }

  /**
   * [BE-P101] 批量创建采集任务
   */
  static async batchCreateCollectionTasks(req: Request, res: Response) {
    const { tasks, businessType } = req.body;
    const traceContext = req.traceContext;

    if (!traceContext) {
      res.status(400).json({ success: false, error: 'Missing trace context' });
      return;
    }

    const { tenantId, shopId, traceId, userId } = traceContext;

    try {
      const collectionService = new ProductCollectionService();
      const taskIds = await collectionService.batchCreateTasks(
        tenantId,
        shopId || '',
        businessType as 'TOC' | 'TOB',
        tasks as Array<{ platform: string; sourceUrl: string }>,
        traceId
      );

      await AuditService.log({
        tenantId,
        shopId: shopId || '',
        traceId,
        userId,
        module: 'PRODUCT',
        action: 'BATCH_CREATE_COLLECTION_TASKS',
        resourceType: 'collection_task',
        resourceId: taskIds.join(','),
        afterSnapshot: { count: taskIds.length },
        result: 'success',
        source: 'console'
      });

      res.status(201).json({ success: true, data: { taskIds, count: taskIds.length } });
    } catch (err: unknown) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      res.status(500).json({ success: false, error: errorMessage });
    }
  }
}
