import { createMachine, createActor } from 'xstate';
import db from '../../config/database';
import { DomainEventBus } from '../../core/runtime/DomainEventBus';
import { logger } from '../../utils/logger';
import { CrawlerService } from '../core/CrawlerService';
import { PricingService, PricingParams } from '../core/PricingService';

/**
 * [BE-P101] 数据采集与清洗服务
 * 负责多平台商品数据采集、清洗、标准化和套利分析
 *
 * 状态流转: RAW_DATA → CLEANED → ANALYZED → READY_FOR_LISTING
 */

// 采集任务状态
export type CollectionState =
  | 'RAW_DATA'
  | 'CLEANED'
  | 'ANALYZED'
  | 'READY_FOR_LISTING'
  | 'FAILED';

// 采集任务事件
export type CollectionEvent =
  | { type: 'CLEAN' }
  | { type: 'ANALYZE' }
  | { type: 'APPROVE' }
  | { type: 'FAIL'; reason: string }
  | { type: 'RETRY' };

// 采集任务上下文
export interface CollectionContext {
  taskId: string;
  tenantId: string;
  shopId: string;
  traceId: string;
  businessType: 'TOC' | 'TOB';
  platform: string;
  sourceUrl: string;
  rawData?: any;
  cleanedData?: any;
  analysisResult?: any;
  errorMessage?: string;
  createdAt: string;
  updatedAt: string;
}

// 采集配置
export interface CollectionConfig {
  platform: string;
  sourceType: 'api' | 'crawler' | 'manual';
  schedule?: string;
  filters?: {
    minPrice?: number;
    maxPrice?: number;
    categories?: string[];
    keywords?: string[];
  };
}

// 清洗后的商品数据
export interface CleanedProduct {
  platform: string;
  productId: string;
  title: string;
  description: string;
  price: number;
  currency: string;
  mainImage: string;
  images: string[];
  attributes: Record<string, string>;
  skus: Array<{
    skuId: string;
    attributes: Record<string, string>;
    price: number;
    stock: number;
  }>;
  shopName: string;
  shopId: string;
  sales: number;
  rating: number;
  physical: {
    lengthCm: number;
    widthCm: number;
    heightCm: number;
    weightKg: number;
  };
}

// 套利分析结果
export interface ArbitrageAnalysis {
  sourcePrice: number;
  targetPrice: number;
  platformFee: number;
  logisticsCost: number;
  taxCost: number;
  adCost: number;
  otherCost: number;
  netProfit: number;
  profitMargin: number;
  isViable: boolean;
  recommendation: 'proceed' | 'review' | 'reject';
}

// 采集状态机
export const collectionStateMachine = createMachine({
  id: 'collection',
  initial: 'RAW_DATA',
  context: {} as CollectionContext,
  states: {
    RAW_DATA: {
      on: {
        CLEAN: 'CLEANED',
        FAIL: 'FAILED',
      },
    },
    CLEANED: {
      on: {
        ANALYZE: 'ANALYZED',
        FAIL: 'FAILED',
      },
    },
    ANALYZED: {
      on: {
        APPROVE: 'READY_FOR_LISTING',
        FAIL: 'FAILED',
      },
    },
    READY_FOR_LISTING: {
      type: 'final',
    },
    FAILED: {
      on: {
        RETRY: 'RAW_DATA',
      },
    },
  },
});

export class ProductCollectionService {
  private static TABLE_NAME = 'cf_product_collection';
  private crawlerService: CrawlerService;

  constructor() {
    this.crawlerService = new CrawlerService();
  }

  /**
   * 初始化数据库表
   */
  static async initTable() {
    const hasTable = await db.schema.hasTable(this.TABLE_NAME);
    if (!hasTable) {
      logger.info(`📦 Creating ${this.TABLE_NAME} table...`);
      await db.schema.createTable(this.TABLE_NAME, (table: any) => {
        table.increments('id').primary();
        table.string('task_id', 64).notNullable().unique();
        table.string('tenant_id', 50).notNullable().index();
        table.string('shop_id', 50).notNullable().index();
        table.string('trace_id', 64).notNullable();
        table.enum('business_type', ['TOC', 'TOB']).notNullable();
        table.string('platform', 50).notNullable();
        table.string('source_url', 1000);
        table.enum('status', [
          'RAW_DATA',
          'CLEANED',
          'ANALYZED',
          'READY_FOR_LISTING',
          'FAILED',
        ]).defaultTo('RAW_DATA');
        table.json('raw_data');
        table.json('cleaned_data');
        table.json('analysis_result');
        table.text('error_message');
        table.timestamps(true, true);

        // 索引优化
        table.index(['tenant_id', 'status'], 'idx_collection_status');
        table.index(['platform', 'status'], 'idx_collection_platform');
        table.index(['created_at'], 'idx_collection_created');
      });
      logger.info(`✅ Table ${this.TABLE_NAME} created`);
    }
  }

  /**
   * 创建采集任务
   */
  async createTask(
    tenantId: string,
    shopId: string,
    businessType: 'TOC' | 'TOB',
    platform: string,
    sourceUrl: string,
    traceId: string
  ): Promise<string> {
    const taskId = `COL-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    const now = new Date().toISOString();

    await db(ProductCollectionService.TABLE_NAME).insert({
      task_id: taskId,
      tenant_id: tenantId,
      shop_id: shopId,
      trace_id: traceId,
      business_type: businessType,
      platform,
      source_url: sourceUrl,
      status: 'RAW_DATA',
      created_at: now,
      updated_at: now,
    });

    this.logOperation(taskId, tenantId, shopId, traceId, businessType, 'TASK_CREATED', {
      platform,
      sourceUrl,
    });

    return taskId;
  }

  /**
   * 执行采集流程
   */
  async executeCollection(taskId: string): Promise<void> {
    const task = await this.getTask(taskId);
    if (!task) {
      throw new Error(`Task not found: ${taskId}`);
    }

    const context: CollectionContext = {
      taskId: task.task_id,
      tenantId: task.tenant_id,
      shopId: task.shop_id,
      traceId: task.trace_id,
      businessType: task.business_type,
      platform: task.platform,
      sourceUrl: task.source_url,
      createdAt: task.created_at,
      updatedAt: task.updated_at,
    };

    const actor = createActor(collectionStateMachine, {
      input: context,
    });

    actor.subscribe((state) => {
      this.handleStateChange(taskId, state.value as CollectionState, state.context);
    });

    actor.start();

    try {
      // Step 1: 采集原始数据
      const rawData = await this.fetchRawData(task);
      await this.updateTask(taskId, {
        raw_data: JSON.stringify(rawData),
        status: 'RAW_DATA',
      });

      // Step 2: 数据清洗
      actor.send({ type: 'CLEAN' });
      const cleanedData = await this.cleanData(rawData, task.platform);
      await this.updateTask(taskId, {
        cleaned_data: JSON.stringify(cleanedData),
        status: 'CLEANED',
      });

      // Step 3: 套利分析
      actor.send({ type: 'ANALYZE' });
      const analysisResult = await this.analyzeArbitrage(
        cleanedData,
        task.businessType,
        task.tenantId
      );
      await this.updateTask(taskId, {
        analysis_result: JSON.stringify(analysisResult),
        status: 'ANALYZED',
      });

      // Step 4: 检查是否可刊登
      if (analysisResult.isViable) {
        actor.send({ type: 'APPROVE' });
        await this.updateTask(taskId, {
          status: 'READY_FOR_LISTING',
        });

        // 发布事件通知
        DomainEventBus.publish('product.collection.completed', {
          taskId,
          tenantId: task.tenant_id,
          shopId: task.shop_id,
          productData: cleanedData,
          analysisResult,
        });
      } else {
        actor.send({
          type: 'FAIL',
          reason: `Arbitrage not viable: ${analysisResult.recommendation}`,
        });
        await this.updateTask(taskId, {
          status: 'FAILED',
          error_message: `Arbitrage analysis failed: ${analysisResult.recommendation}`,
        });
      }
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';
      actor.send({ type: 'FAIL', reason: errorMessage });
      await this.updateTask(taskId, {
        status: 'FAILED',
        error_message: errorMessage,
      });

      this.logOperation(
        taskId,
        task.tenant_id,
        task.shop_id,
        task.trace_id,
        task.business_type,
        'COLLECTION_FAILED',
        { error: errorMessage }
      );
    }

    actor.stop();
  }

  /**
   * 获取原始数据
   */
  private async fetchRawData(task: any): Promise<any> {
    // 使用 CrawlerService 采集数据
    const rawData = await this.crawlerService.crawl(task.source_url);
    return rawData;
  }

  /**
   * 数据清洗和标准化
   */
  private async cleanData(rawData: any, platform: string): Promise<CleanedProduct> {
    // 标准化价格
    const price = this.normalizePrice(rawData.price, rawData.currency);

    // 标准化物理属性
    const physical = this.normalizePhysicalAttributes(rawData);

    // 清洗图片URL
    const images = this.cleanImageUrls(rawData.images || [rawData.mainImage]);

    // 标准化SKU
    const skus = this.normalizeSkus(rawData.skus || [], price);

    // 清洗标题和描述
    const title = this.cleanText(rawData.title || '');
    const description = this.cleanText(rawData.description || '');

    return {
      platform,
      productId: rawData.productId || rawData.id || '',
      title,
      description,
      price,
      currency: rawData.currency || 'CNY',
      mainImage: images[0] || '',
      images,
      attributes: this.normalizeAttributes(rawData.attributes || {}),
      skus,
      shopName: rawData.shopName || rawData.shop || '',
      shopId: rawData.shopId || rawData.shop_id || '',
      sales: parseInt(rawData.sales) || 0,
      rating: parseFloat(rawData.rating) || 0,
      physical,
    };
  }

  /**
   * 标准化价格
   */
  private normalizePrice(price: any, currency: string): number {
    const parsed = parseFloat(price);
    if (isNaN(parsed) || parsed < 0) {
      return 0;
    }
    // 保留2位小数
    return Math.round(parsed * 100) / 100;
  }

  /**
   * 标准化物理属性
   */
  private normalizePhysicalAttributes(rawData: any): {
    lengthCm: number;
    widthCm: number;
    heightCm: number;
    weightKg: number;
  } {
    // 转换各种单位到标准单位 (cm, kg)
    const lengthCm = this.convertLength(rawData.length || rawData.length_cm || 0);
    const widthCm = this.convertLength(rawData.width || rawData.width_cm || 0);
    const heightCm = this.convertLength(rawData.height || rawData.height_cm || 0);
    const weightKg = this.convertWeight(rawData.weight || rawData.weight_kg || 0);

    return {
      lengthCm,
      widthCm,
      heightCm,
      weightKg,
    };
  }

  /**
   * 转换长度到厘米
   */
  private convertLength(value: any): number {
    const parsed = parseFloat(value);
    if (isNaN(parsed)) return 0;
    // 假设输入已经是cm或需要转换
    return Math.round(parsed * 100) / 100;
  }

  /**
   * 转换重量到千克
   */
  private convertWeight(value: any): number {
    const parsed = parseFloat(value);
    if (isNaN(parsed)) return 0;
    // 假设输入是克，转换为千克
    if (parsed > 1000) {
      return Math.round((parsed / 1000) * 1000) / 1000;
    }
    return Math.round(parsed * 1000) / 1000;
  }

  /**
   * 清洗图片URL
   */
  private cleanImageUrls(images: any[]): string[] {
    if (!Array.isArray(images)) return [];

    return images
      .filter((url) => typeof url === 'string' && url.length > 0)
      .map((url) => {
        // 移除URL中的跟踪参数
        try {
          const urlObj = new URL(url);
          // 保留必要的参数，移除跟踪参数
          const trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'ref'];
          trackingParams.forEach((param) => urlObj.searchParams.delete(param));
          return urlObj.toString();
        } catch {
          return url;
        }
      })
      .slice(0, 10); // 最多保留10张图片
  }

  /**
   * 标准化SKU
   */
  private normalizeSkus(
    skus: any[],
    defaultPrice: number
  ): Array<{
    skuId: string;
    attributes: Record<string, string>;
    price: number;
    stock: number;
  }> {
    if (!Array.isArray(skus) || skus.length === 0) {
      return [];
    }

    return skus.map((sku) => ({
      skuId: sku.skuId || sku.id || '',
      attributes: this.normalizeAttributes(sku.attributes || {}),
      price: this.normalizePrice(sku.price || defaultPrice, sku.currency || 'CNY'),
      stock: parseInt(sku.stock) || 0,
    }));
  }

  /**
   * 标准化属性
   */
  private normalizeAttributes(attributes: any): Record<string, string> {
    if (typeof attributes !== 'object' || attributes === null) {
      return {};
    }

    const normalized: Record<string, string> = {};
    for (const [key, value] of Object.entries(attributes)) {
      normalized[key.trim().toLowerCase()] = String(value).trim();
    }
    return normalized;
  }

  /**
   * 清洗文本
   */
  private cleanText(text: string): string {
    if (!text) return '';
    return text
      .replace(/\s+/g, ' ') // 合并多个空格
      .replace(/[\n\r\t]+/g, ' ') // 替换换行符
      .trim();
  }

  /**
   * 套利分析
   */
  private async analyzeArbitrage(
    cleanedData: CleanedProduct,
    businessType: 'TOC' | 'TOB',
    tenantId: string
  ): Promise<ArbitrageAnalysis> {
    // 计算物流成本（基于重量和体积）
    const logisticsCost = this.calculateLogisticsCost(cleanedData.physical);

    // 构建定价参数
    const pricingParams: PricingParams = {
      sellingPrice: cleanedData.price * 1.5, // 预估售价（采购价的1.5倍）
      purchasePrice: cleanedData.price,
      platform: cleanedData.platform,
      countryCode: 'US',
      logisticsCost,
      isB2B: businessType === 'TOB',
    };

    // 调用 PricingService 计算净利润
    const profitSnapshot = await PricingService.calculateNetProfit(pricingParams);

    // 风险检查
    const riskCheck = PricingService.checkRisk(profitSnapshot, businessType === 'TOB');

    // 计算其他成本
    const platformFee = profitSnapshot.platformFee;
    const taxCost = profitSnapshot.tax;
    const adCost = profitSnapshot.adAmortization;
    const otherCost = profitSnapshot.fxHedging + profitSnapshot.afterSalesLoss;

    // 利润红线检查
    let isViable = false;
    let recommendation: 'proceed' | 'review' | 'reject' = 'reject';

    if (businessType === 'TOB') {
      // B2B 利润率 < 15% 禁止报价
      if (riskCheck.level === 'BLOCK') {
        isViable = false;
        recommendation = 'reject';
      } else if (riskCheck.level === 'WARN') {
        isViable = true;
        recommendation = 'review';
      } else {
        isViable = true;
        recommendation = 'proceed';
      }
    } else {
      // B2C 利润率 < 20% 触发风控预警
      if (riskCheck.level === 'WARN' || riskCheck.level === 'BLOCK') {
        isViable = true;
        recommendation = 'review';
      } else {
        isViable = true;
        recommendation = 'proceed';
      }
    }

    return {
      sourcePrice: cleanedData.price,
      targetPrice: profitSnapshot.sellingPrice,
      platformFee,
      logisticsCost,
      taxCost,
      adCost,
      otherCost,
      netProfit: profitSnapshot.netProfit,
      profitMargin: profitSnapshot.profitRate * 100,
      isViable,
      recommendation,
    };
  }

  /**
   * 计算物流成本
   */
  private calculateLogisticsCost(physical: {
    lengthCm: number;
    widthCm: number;
    heightCm: number;
    weightKg: number;
  }): number {
    // 体积重量 (kg) = 长(cm) × 宽(cm) × 高(cm) / 5000
    const volumeWeight = (physical.lengthCm * physical.widthCm * physical.heightCm) / 5000;

    // 计费重量取实际重量和体积重量的较大值
    const chargeableWeight = Math.max(physical.weightKg, volumeWeight);

    // 基础运费：首重 10 USD，续重 5 USD/kg
    const baseCost = 10;
    const additionalCost = Math.max(0, chargeableWeight - 0.5) * 5;

    return Math.round((baseCost + additionalCost) * 100) / 100;
  }

  /**
   * 获取任务详情
   */
  private async getTask(taskId: string): Promise<any> {
    return db(ProductCollectionService.TABLE_NAME).where('task_id', taskId).first();
  }

  /**
   * 更新任务
   */
  private async updateTask(
    taskId: string,
    updates: Partial<{
      status: CollectionState;
      raw_data: string;
      cleaned_data: string;
      analysis_result: string;
      error_message: string;
    }>
  ): Promise<void> {
    await db(ProductCollectionService.TABLE_NAME).where('task_id', taskId).update({
      ...updates,
      updated_at: new Date().toISOString(),
    });
  }

  /**
   * 处理状态变更
   */
  private handleStateChange(
    taskId: string,
    newState: CollectionState,
    context: CollectionContext
  ): void {
    this.logOperation(
      taskId,
      context.tenantId,
      context.shopId,
      context.traceId,
      context.businessType,
      'STATE_CHANGED',
      { newState }
    );
  }

  /**
   * 记录操作日志
   */
  private logOperation(
    taskId: string,
    tenantId: string,
    shopId: string,
    traceId: string,
    businessType: 'TOC' | 'TOB',
    operation: string,
    details: any
  ): void {
    logger.info(
      `[ProductCollectionService] ${operation}`,
      {
        taskId,
        tenantId,
        shopId,
        traceId,
        businessType,
        operation,
        details,
      }
    );
  }

  /**
   * 获取任务列表
   */
  async getTasks(
    tenantId: string,
    filters?: {
      status?: CollectionState;
      platform?: string;
      limit?: number;
      offset?: number;
    }
  ): Promise<any[]> {
    let query = db(ProductCollectionService.TABLE_NAME).where('tenant_id', tenantId);

    if (filters?.status) {
      query = query.where('status', filters.status);
    }
    if (filters?.platform) {
      query = query.where('platform', filters.platform);
    }

    query = query.orderBy('created_at', 'desc');

    if (filters?.limit) {
      query = query.limit(filters.limit);
    }
    if (filters?.offset) {
      query = query.offset(filters.offset);
    }

    return query.select('*');
  }

  /**
   * 重试失败任务
   */
  async retryTask(taskId: string): Promise<void> {
    const task = await this.getTask(taskId);
    if (!task) {
      throw new Error(`Task not found: ${taskId}`);
    }

    if (task.status !== 'FAILED') {
      throw new Error(`Task ${taskId} is not in FAILED state`);
    }

    await this.updateTask(taskId, {
      status: 'RAW_DATA',
      error_message: '',
    });

    await this.executeCollection(taskId);
  }

  /**
   * 批量创建采集任务
   */
  async batchCreateTasks(
    tenantId: string,
    shopId: string,
    businessType: 'TOC' | 'TOB',
    tasks: Array<{
      platform: string;
      sourceUrl: string;
    }>,
    traceId: string
  ): Promise<string[]> {
    const taskIds: string[] = [];

    for (const task of tasks) {
      const taskId = await this.createTask(
        tenantId,
        shopId,
        businessType,
        task.platform,
        task.sourceUrl,
        traceId
      );
      taskIds.push(taskId);
    }

    return taskIds;
  }
}
