import db from '../../config/database';
import { logger } from '../../utils/logger';

export type AttributionModel = 'FIRST_CLICK' | 'LAST_CLICK' | 'LINEAR' | 'TIME_DECAY';

/**
 * [BIZ_MKT_40] 多触点归因与利润分析 (Multi-Touch Attribution Engine)
 * @description 核心逻辑：基于用户行为日志与订单数据，实现多维度流量归因，识破虚假 ROAS。
 */
export class MultiTouchAttributionService {
  private static readonly ATTRIBUTION_TABLE = 'cf_order_attributions';
  private static readonly PIXEL_LOGS_TABLE = 'cf_pixel_logs';

  /**
   * 对订单执行归因分析
   */
  static async attributeOrder(tenantId: string, orderId: string, model: AttributionModel = 'LINEAR') {
    logger.info(`[Attribution] Starting attribution for order: ${orderId} using model: ${model}`);

    // 1. 获取订单基础数据
    const order = await db('cf_consumer_orders').where({ tenant_id: tenantId, order_id: orderId }).first();
    if (!order) {
      logger.warn(`[Attribution] Order not found: ${orderId}`);
      return null;
    }

    // 2. 获取该用户的点击流日志 (基于 customer_id 或 session_id)
    // 假设日志中包含 utm_source, utm_campaign 等信息
    const logs = await db(this.PIXEL_LOGS_TABLE)
      .where({ tenant_id: tenantId, customer_id: order.customer_id })
      .andWhere('created_at', '<=', order.created_at)
      .orderBy('created_at', 'asc');

    if (logs.length === 0) {
      logger.info(`[Attribution] No click logs found for order ${orderId}. Marking as ORGANIC.`);
      return this.saveAttribution(tenantId, orderId, 'ORGANIC', 'DIRECT', 1.0, order.total_amount);
    }

    // 3. 执行归因算法
    const attributions = this.calculateAttribution(logs, order.total_amount, model);

    // 4. 存储结果
    for (const attr of attributions) {
      await this.saveAttribution(tenantId, orderId, attr.source, attr.campaign, attr.weight, attr.attributedValue);
    }

    return attributions;
  }

  /**
   * 归因算法实现
   */
  private static calculateAttribution(logs: any[], totalValue: number, model: AttributionModel) {
    const results: any[] = [];
    const n = logs.length;

    switch (model) {
      case 'FIRST_CLICK':
        results.push({
          source: logs[0].utm_source,
          campaign: logs[0].utm_campaign,
          weight: 1.0,
          attributedValue: totalValue
        });
        break;

      case 'LAST_CLICK':
        results.push({
          source: logs[n - 1].utm_source,
          campaign: logs[n - 1].utm_campaign,
          weight: 1.0,
          attributedValue: totalValue
        });
        break;

      case 'LINEAR':
        const weight = 1.0 / n;
        logs.forEach(log => {
          results.push({
            source: log.utm_source,
            campaign: log.utm_campaign,
            weight: weight,
            attributedValue: totalValue * weight
          });
        });
        break;

      case 'TIME_DECAY':
        // 简化版时间衰减：最近的权重更高
        let totalWeight = 0;
        const decayWeights = logs.map((_, i) => {
          const w = Math.pow(2, i); // 2^0, 2^1, ...
          totalWeight += w;
          return w;
        });

        logs.forEach((log, i) => {
          const w = decayWeights[i] / totalWeight;
          results.push({
            source: log.utm_source,
            campaign: log.utm_campaign,
            weight: w,
            attributedValue: totalValue * w
          });
        });
        break;
    }

    // 聚合相同 source/campaign 的权重
    const aggregated = results.reduce((acc, curr) => {
      const key = `${curr.source}-${curr.campaign}`;
      if (!acc[key]) {
        acc[key] = { ...curr };
      } else {
        acc[key].weight += curr.weight;
        acc[key].attributedValue += curr.attributedValue;
      }
      return acc;
    }, {} as any);

    return Object.values(aggregated);
  }

  /**
   * 存储归因结果
   */
  private static async saveAttribution(
    tenantId: string,
    orderId: string,
    source: string,
    campaign: string,
    weight: number,
    value: number
  ) {
    const record = {
      id: `ATTR-${orderId}-${source}-${campaign}`,
      tenant_id: tenantId,
      order_id: orderId,
      source: source || 'UNKNOWN',
      campaign: campaign || 'UNKNOWN',
      weight: Number(weight.toFixed(4)),
      attributed_value: Number(value.toFixed(2)),
      created_at: new Date()
    };

    await db(this.ATTRIBUTION_TABLE)
      .insert(record)
      .onConflict(['id'])
      .merge();

    return record;
  }

  /**
   * 初始化数据库表
   */
  static async initTable() {
    const hasTable = await db.schema.hasTable(this.ATTRIBUTION_TABLE);
    if (!hasTable) {
      logger.info(`📦 Creating ${this.ATTRIBUTION_TABLE} table...`);
      await db.schema.createTable(this.ATTRIBUTION_TABLE, (table) => {
        table.string('id', 128).primary();
        table.string('tenant_id', 64).notNullable().index();
        table.string('order_id', 64).notNullable().index();
        table.string('source', 64);
        table.string('campaign', 64);
        table.decimal('weight', 10, 4);
        table.decimal('attributed_value', 15, 2);
        table.timestamp('created_at').defaultTo(db.fn.now());
      });
    }

    // 同时也确保 cf_pixel_logs 表存在 (用于测试)
    const hasLogsTable = await db.schema.hasTable(this.PIXEL_LOGS_TABLE);
    if (!hasLogsTable) {
      logger.info(`📦 Creating ${this.PIXEL_LOGS_TABLE} table...`);
      await db.schema.createTable(this.PIXEL_LOGS_TABLE, (table) => {
        table.increments('id').primary();
        table.string('tenant_id', 64).notNullable().index();
        table.string('customer_id', 64).index();
        table.string('utm_source', 64);
        table.string('utm_campaign', 64);
        table.string('event_type', 32); // CLICK, PAGE_VIEW
        table.timestamp('created_at').defaultTo(db.fn.now());
      });
    }
  }
}
