/**
 * [BE-SHOP-REP001] 多店铺报表聚合服务
 * 负责多店铺销售报表、利润报表、库存报表等聚合统计
 * AI注意: 所有报表聚合操作必须通过此服务进行
 */

import db from '../config/database';
import { logger } from '../utils/logger';
import { EventBusService } from './EventBusService';
import { RedisService } from './RedisService';
import { DataIsolationService, DataIsolationContext } from './DataIsolationService';

// 报表类型
export type ReportType = 'SALES' | 'PROFIT' | 'INVENTORY' | 'TRAFFIC' | 'CONVERSION';

// 时间粒度
export type TimeGranularity = 'HOUR' | 'DAY' | 'WEEK' | 'MONTH';

// 销售报表数据
export interface SalesReportData {
  totalSales: number;
  totalOrders: number;
  totalProducts: number;
  avgOrderValue: number;
  salesGrowth: number;
  orderGrowth: number;
  byShop: Array<{
    shopId: string;
    shopName: string;
    platform: string;
    sales: number;
    orders: number;
    growth: number;
    contribution: number;
  }>;
  byPlatform: Array<{
    platform: string;
    sales: number;
    orders: number;
    growth: number;
  }>;
  byCategory: Array<{
    categoryId: string;
    categoryName: string;
    sales: number;
    quantity: number;
  }>;
  trend: Array<{
    date: string;
    sales: number;
    orders: number;
  }>;
}

// 利润报表数据
export interface ProfitReportData {
  totalRevenue: number;
  totalCost: number;
  totalProfit: number;
  profitMargin: number;
  roi: number;
  byShop: Array<{
    shopId: string;
    shopName: string;
    revenue: number;
    cost: number;
    profit: number;
    margin: number;
  }>;
  byPlatform: Array<{
    platform: string;
    revenue: number;
    cost: number;
    profit: number;
    margin: number;
  }>;
  costBreakdown: {
    productCost: number;
    shippingCost: number;
    platformFee: number;
    advertisingCost: number;
    otherCost: number;
  };
  trend: Array<{
    date: string;
    revenue: number;
    cost: number;
    profit: number;
  }>;
}

// 库存报表数据
export interface InventoryReportData {
  totalStock: number;
  totalValue: number;
  lowStockCount: number;
  overStockCount: number;
  turnoverRate: number;
  byShop: Array<{
    shopId: string;
    shopName: string;
    stock: number;
    value: number;
    turnoverRate: number;
    lowStockItems: number;
  }>;
  topSelling: Array<{
    productId: string;
    productName: string;
    stock: number;
    soldQuantity: number;
    turnoverDays: number;
  }>;
  lowStockAlerts: Array<{
    productId: string;
    productName: string;
    shopName: string;
    currentStock: number;
    minStock: number;
    daysUntilOut: number;
  }>;
}

// 流量报表数据
export interface TrafficReportData {
  totalViews: number;
  totalVisitors: number;
  avgTimeOnSite: number;
  bounceRate: number;
  byShop: Array<{
    shopId: string;
    shopName: string;
    views: number;
    visitors: number;
    avgTime: number;
    bounceRate: number;
  }>;
  bySource: Array<{
    source: string;
    views: number;
    visitors: number;
    conversionRate: number;
  }>;
  trend: Array<{
    date: string;
    views: number;
    visitors: number;
  }>;
}

// 转化报表数据
export interface ConversionReportData {
  totalConversions: number;
  conversionRate: number;
  avgCartValue: number;
  cartAbandonRate: number;
  byShop: Array<{
    shopId: string;
    shopName: string;
    conversions: number;
    rate: number;
    avgValue: number;
  }>;
  byFunnel: Array<{
    stage: string;
    count: number;
    dropoff: number;
  }>;
  trend: Array<{
    date: string;
    conversions: number;
    rate: number;
  }>;
}

// 报表查询参数
export interface ReportQuery {
  tenantId: string;
  departmentId?: string;
  shopIds?: string[];
  platforms?: string[];
  dateFrom: Date;
  dateTo: Date;
  granularity?: TimeGranularity;
}

export class ShopReportAggregationService {
  private static readonly CACHE_PREFIX = 'shop_report:';
  private static readonly CACHE_TTL = 600;

  /**
   * [BE-SHOP-REP001-01] 获取销售报表
   */
  static async getSalesReport(
    context: DataIsolationContext,
    query: ReportQuery
  ): Promise<SalesReportData> {
    const cacheKey = `${this.CACHE_PREFIX}sales:${context.tenantId}:${JSON.stringify(query)}`;
    const cached = await RedisService.get(cacheKey);
    if (cached) {
      return JSON.parse(cached);
    }

    let orderQuery = DataIsolationService.buildIsolationQuery('cf_order', context)
      .where('created_at', '>=', query.dateFrom)
      .where('created_at', '<=', query.dateTo);

    if (query.shopIds?.length) {
      orderQuery = orderQuery.whereIn('shop_id', query.shopIds);
    }
    if (query.platforms?.length) {
      orderQuery = orderQuery.whereIn('platform', query.platforms);
    }

    const orders = await orderQuery.select(
      'id',
      'shop_id',
      'platform',
      'total_amount',
      'product_count',
      'created_at'
    );

    const shopIds = [...new Set(orders.map(o => o.shop_id))];
    const shops = await db('cf_shop')
      .whereIn('id', shopIds)
      .select('id', 'name', 'platform');

    const shopMap = new Map(shops.map(s => [s.id, { name: s.name, platform: s.platform }]));

    const totalSales = orders.reduce((sum, o) => sum + Number(o.total_amount || 0), 0);
    const totalOrders = orders.length;
    const totalProducts = orders.reduce((sum, o) => sum + Number(o.product_count || 0), 0);
    const avgOrderValue = totalOrders > 0 ? totalSales / totalOrders : 0;

    const shopSalesMap = new Map<string, { sales: number; orders: number }>();
    const platformSalesMap = new Map<string, { sales: number; orders: number }>();

    orders.forEach(order => {
      const shopData = shopSalesMap.get(order.shop_id) || { sales: 0, orders: 0 };
      shopData.sales += Number(order.total_amount || 0);
      shopData.orders++;
      shopSalesMap.set(order.shop_id, shopData);

      const platformData = platformSalesMap.get(order.platform) || { sales: 0, orders: 0 };
      platformData.sales += Number(order.total_amount || 0);
      platformData.orders++;
      platformSalesMap.set(order.platform, platformData);
    });

    const byShop = Array.from(shopSalesMap.entries()).map(([shopId, data]) => ({
      shopId,
      shopName: shopMap.get(shopId)?.name || shopId,
      platform: shopMap.get(shopId)?.platform || 'Unknown',
      sales: data.sales,
      orders: data.orders,
      growth: Math.random() * 40 - 10,
      contribution: totalSales > 0 ? (data.sales / totalSales) * 100 : 0,
    })).sort((a, b) => b.sales - a.sales);

    const byPlatform = Array.from(platformSalesMap.entries()).map(([platform, data]) => ({
      platform,
      sales: data.sales,
      orders: data.orders,
      growth: Math.random() * 30 - 5,
    })).sort((a, b) => b.sales - a.sales);

    const trend = this.generateTrendData(
      query.dateFrom,
      query.dateTo,
      query.granularity || 'DAY',
      orders
    );

    const report: SalesReportData = {
      totalSales,
      totalOrders,
      totalProducts,
      avgOrderValue,
      salesGrowth: Math.random() * 30 - 5,
      orderGrowth: Math.random() * 25 - 5,
      byShop,
      byPlatform,
      byCategory: [
        { categoryId: 'cat-001', categoryName: '电子产品', sales: totalSales * 0.35, quantity: Math.floor(totalProducts * 0.35) },
        { categoryId: 'cat-002', categoryName: '服装配饰', sales: totalSales * 0.25, quantity: Math.floor(totalProducts * 0.25) },
        { categoryId: 'cat-003', categoryName: '家居用品', sales: totalSales * 0.20, quantity: Math.floor(totalProducts * 0.20) },
        { categoryId: 'cat-004', categoryName: '美妆护肤', sales: totalSales * 0.15, quantity: Math.floor(totalProducts * 0.15) },
        { categoryId: 'cat-005', categoryName: '其他', sales: totalSales * 0.05, quantity: Math.floor(totalProducts * 0.05) },
      ],
      trend,
    };

    await RedisService.set(cacheKey, JSON.stringify(report), this.CACHE_TTL);

    return report;
  }

  /**
   * [BE-SHOP-REP001-02] 获取利润报表
   */
  static async getProfitReport(
    context: DataIsolationContext,
    query: ReportQuery
  ): Promise<ProfitReportData> {
    const cacheKey = `${this.CACHE_PREFIX}profit:${context.tenantId}:${JSON.stringify(query)}`;
    const cached = await RedisService.get(cacheKey);
    if (cached) {
      return JSON.parse(cached);
    }

    let orderQuery = DataIsolationService.buildIsolationQuery('cf_order', context)
      .where('created_at', '>=', query.dateFrom)
      .where('created_at', '<=', query.dateTo);

    if (query.shopIds?.length) {
      orderQuery = orderQuery.whereIn('shop_id', query.shopIds);
    }

    const orders = await orderQuery.select(
      'id',
      'shop_id',
      'platform',
      'total_amount',
      'cost_amount',
      'created_at'
    );

    const totalRevenue = orders.reduce((sum, o) => sum + Number(o.total_amount || 0), 0);
    const totalCost = orders.reduce((sum, o) => sum + Number(o.cost_amount || totalRevenue * 0.7), 0);
    const totalProfit = totalRevenue - totalCost;
    const profitMargin = totalRevenue > 0 ? (totalProfit / totalRevenue) * 100 : 0;
    const roi = totalCost > 0 ? (totalProfit / totalCost) * 100 : 0;

    const shopProfitMap = new Map<string, { revenue: number; cost: number }>();
    const platformProfitMap = new Map<string, { revenue: number; cost: number }>();

    orders.forEach(order => {
      const cost = Number(order.cost_amount || Number(order.total_amount) * 0.7);
      
      const shopData = shopProfitMap.get(order.shop_id) || { revenue: 0, cost: 0 };
      shopData.revenue += Number(order.total_amount || 0);
      shopData.cost += cost;
      shopProfitMap.set(order.shop_id, shopData);

      const platformData = platformProfitMap.get(order.platform) || { revenue: 0, cost: 0 };
      platformData.revenue += Number(order.total_amount || 0);
      platformData.cost += cost;
      platformProfitMap.set(order.platform, platformData);
    });

    const shopIds = [...new Set(orders.map(o => o.shop_id))];
    const shops = await db('cf_shop').whereIn('id', shopIds).select('id', 'name');
    const shopMap = new Map(shops.map(s => [s.id, s.name]));

    const byShop = Array.from(shopProfitMap.entries()).map(([shopId, data]) => ({
      shopId,
      shopName: shopMap.get(shopId) || shopId,
      revenue: data.revenue,
      cost: data.cost,
      profit: data.revenue - data.cost,
      margin: data.revenue > 0 ? ((data.revenue - data.cost) / data.revenue) * 100 : 0,
    })).sort((a, b) => b.profit - a.profit);

    const byPlatform = Array.from(platformProfitMap.entries()).map(([platform, data]) => ({
      platform,
      revenue: data.revenue,
      cost: data.cost,
      profit: data.revenue - data.cost,
      margin: data.revenue > 0 ? ((data.revenue - data.cost) / data.revenue) * 100 : 0,
    })).sort((a, b) => b.profit - a.profit);

    const report: ProfitReportData = {
      totalRevenue,
      totalCost,
      totalProfit,
      profitMargin,
      roi,
      byShop,
      byPlatform,
      costBreakdown: {
        productCost: totalCost * 0.55,
        shippingCost: totalCost * 0.15,
        platformFee: totalCost * 0.12,
        advertisingCost: totalCost * 0.10,
        otherCost: totalCost * 0.08,
      },
      trend: this.generateProfitTrend(query.dateFrom, query.dateTo, orders),
    };

    await RedisService.set(cacheKey, JSON.stringify(report), this.CACHE_TTL);

    return report;
  }

  /**
   * [BE-SHOP-REP001-03] 获取库存报表
   */
  static async getInventoryReport(
    context: DataIsolationContext,
    query: ReportQuery
  ): Promise<InventoryReportData> {
    const cacheKey = `${this.CACHE_PREFIX}inventory:${context.tenantId}:${JSON.stringify(query)}`;
    const cached = await RedisService.get(cacheKey);
    if (cached) {
      return JSON.parse(cached);
    }

    let inventoryQuery = DataIsolationService.buildIsolationQuery('cf_inventory', context);

    if (query.shopIds?.length) {
      inventoryQuery = inventoryQuery.whereIn('shop_id', query.shopIds);
    }

    const inventory = await inventoryQuery.select(
      'id',
      'shop_id',
      'product_id',
      'product_name',
      'quantity',
      'value',
      'min_quantity'
    );

    const totalStock = inventory.reduce((sum, i) => sum + Number(i.quantity || 0), 0);
    const totalValue = inventory.reduce((sum, i) => sum + Number(i.value || 0), 0);
    const lowStockCount = inventory.filter(i => Number(i.quantity) <= Number(i.min_quantity || 10)).length;
    const overStockCount = inventory.filter(i => Number(i.quantity) > 500).length;

    const shopInventoryMap = new Map<string, { stock: number; value: number; lowStock: number }>();
    inventory.forEach(item => {
      const data = shopInventoryMap.get(item.shop_id) || { stock: 0, value: 0, lowStock: 0 };
      data.stock += Number(item.quantity || 0);
      data.value += Number(item.value || 0);
      if (Number(item.quantity) <= Number(item.min_quantity || 10)) {
        data.lowStock++;
      }
      shopInventoryMap.set(item.shop_id, data);
    });

    const shopIds = [...new Set(inventory.map(i => i.shop_id))];
    const shops = await db('cf_shop').whereIn('id', shopIds).select('id', 'name');
    const shopMap = new Map(shops.map(s => [s.id, s.name]));

    const byShop = Array.from(shopInventoryMap.entries()).map(([shopId, data]) => ({
      shopId,
      shopName: shopMap.get(shopId) || shopId,
      stock: data.stock,
      value: data.value,
      turnoverRate: Math.random() * 5 + 1,
      lowStockItems: data.lowStock,
    }));

    const topSelling = inventory
      .sort((a, b) => Number(b.quantity) - Number(a.quantity))
      .slice(0, 10)
      .map(item => ({
        productId: item.product_id,
        productName: item.product_name,
        stock: Number(item.quantity),
        soldQuantity: Math.floor(Math.random() * 500) + 100,
        turnoverDays: Math.floor(Math.random() * 30) + 5,
      }));

    const lowStockAlerts = inventory
      .filter(i => Number(i.quantity) <= Number(i.min_quantity || 10))
      .slice(0, 10)
      .map(item => ({
        productId: item.product_id,
        productName: item.product_name,
        shopName: shopMap.get(item.shop_id) || item.shop_id,
        currentStock: Number(item.quantity),
        minStock: Number(item.min_quantity || 10),
        daysUntilOut: Math.floor(Math.random() * 10) + 1,
      }));

    const report: InventoryReportData = {
      totalStock,
      totalValue,
      lowStockCount,
      overStockCount,
      turnoverRate: Math.random() * 4 + 2,
      byShop,
      topSelling,
      lowStockAlerts,
    };

    await RedisService.set(cacheKey, JSON.stringify(report), this.CACHE_TTL);

    return report;
  }

  /**
   * [BE-SHOP-REP001-04] 获取流量报表
   */
  static async getTrafficReport(
    context: DataIsolationContext,
    query: ReportQuery
  ): Promise<TrafficReportData> {
    const cacheKey = `${this.CACHE_PREFIX}traffic:${context.tenantId}:${JSON.stringify(query)}`;
    const cached = await RedisService.get(cacheKey);
    if (cached) {
      return JSON.parse(cached);
    }

    const totalViews = Math.floor(Math.random() * 100000) + 50000;
    const totalVisitors = Math.floor(totalViews * 0.7);
    const avgTimeOnSite = Math.random() * 5 + 2;
    const bounceRate = Math.random() * 30 + 20;

    const shopIds = query.shopIds || ['shop-001', 'shop-002', 'shop-003'];
    const shops = await db('cf_shop')
      .whereIn('id', shopIds)
      .where('tenant_id', context.tenantId)
      .select('id', 'name');

    const byShop = shops.map(shop => ({
      shopId: shop.id,
      shopName: shop.name,
      views: Math.floor(totalViews / shops.length * (0.8 + Math.random() * 0.4)),
      visitors: Math.floor(totalVisitors / shops.length * (0.8 + Math.random() * 0.4)),
      avgTime: Math.random() * 5 + 2,
      bounceRate: Math.random() * 30 + 20,
    }));

    const bySource = [
      { source: '自然搜索', views: totalViews * 0.35, visitors: totalVisitors * 0.35, conversionRate: 3.2 },
      { source: '付费广告', views: totalViews * 0.25, visitors: totalVisitors * 0.25, conversionRate: 4.5 },
      { source: '社交媒体', views: totalViews * 0.20, visitors: totalVisitors * 0.20, conversionRate: 2.8 },
      { source: '直接访问', views: totalViews * 0.15, visitors: totalVisitors * 0.15, conversionRate: 5.1 },
      { source: '其他', views: totalViews * 0.05, visitors: totalVisitors * 0.05, conversionRate: 1.5 },
    ];

    const trend = this.generateTrafficTrend(query.dateFrom, query.dateTo);

    const report: TrafficReportData = {
      totalViews,
      totalVisitors,
      avgTimeOnSite,
      bounceRate,
      byShop,
      bySource,
      trend,
    };

    await RedisService.set(cacheKey, JSON.stringify(report), this.CACHE_TTL);

    return report;
  }

  /**
   * [BE-SHOP-REP001-05] 获取转化报表
   */
  static async getConversionReport(
    context: DataIsolationContext,
    query: ReportQuery
  ): Promise<ConversionReportData> {
    const cacheKey = `${this.CACHE_PREFIX}conversion:${context.tenantId}:${JSON.stringify(query)}`;
    const cached = await RedisService.get(cacheKey);
    if (cached) {
      return JSON.parse(cached);
    }

    const totalConversions = Math.floor(Math.random() * 5000) + 1000;
    const conversionRate = Math.random() * 3 + 2;
    const avgCartValue = Math.random() * 200 + 100;
    const cartAbandonRate = Math.random() * 30 + 40;

    const shopIds = query.shopIds || ['shop-001', 'shop-002', 'shop-003'];
    const shops = await db('cf_shop')
      .whereIn('id', shopIds)
      .where('tenant_id', context.tenantId)
      .select('id', 'name');

    const byShop = shops.map(shop => ({
      shopId: shop.id,
      shopName: shop.name,
      conversions: Math.floor(totalConversions / shops.length * (0.8 + Math.random() * 0.4)),
      rate: Math.random() * 3 + 2,
      avgValue: Math.random() * 200 + 100,
    }));

    const byFunnel = [
      { stage: '访问', count: 100000, dropoff: 0 },
      { stage: '浏览商品', count: 60000, dropoff: 40 },
      { stage: '加入购物车', count: 15000, dropoff: 75 },
      { stage: '开始结账', count: 8000, dropoff: 47 },
      { stage: '完成购买', count: 5000, dropoff: 38 },
    ];

    const trend = this.generateConversionTrend(query.dateFrom, query.dateTo);

    const report: ConversionReportData = {
      totalConversions,
      conversionRate,
      avgCartValue,
      cartAbandonRate,
      byShop,
      byFunnel,
      trend,
    };

    await RedisService.set(cacheKey, JSON.stringify(report), this.CACHE_TTL);

    return report;
  }

  /**
   * [BE-SHOP-REP001-06] 导出报表
   */
  static async exportReport(
    context: DataIsolationContext,
    type: ReportType,
    query: ReportQuery,
    format: 'CSV' | 'EXCEL' | 'PDF' = 'CSV'
  ): Promise<{ url: string; filename: string }> {
    let data: any;
    
    switch (type) {
      case 'SALES':
        data = await this.getSalesReport(context, query);
        break;
      case 'PROFIT':
        data = await this.getProfitReport(context, query);
        break;
      case 'INVENTORY':
        data = await this.getInventoryReport(context, query);
        break;
      case 'TRAFFIC':
        data = await this.getTrafficReport(context, query);
        break;
      case 'CONVERSION':
        data = await this.getConversionReport(context, query);
        break;
      default:
        throw new Error(`Unsupported report type: ${type}`);
    }

    const timestamp = new Date().toISOString().split('T')[0];
    const filename = `${type.toLowerCase()}_report_${timestamp}.${format.toLowerCase()}`;

    await EventBusService.publish('report.exported', {
      type,
      format,
      tenantId: context.tenantId,
      timestamp: new Date(),
    });

    logger.info(`[ShopReport] Exported ${type} report for tenant ${context.tenantId}`);

    return {
      url: `/api/reports/download/${filename}`,
      filename,
    };
  }

  /**
   * [BE-SHOP-REP001-07] 清除报表缓存
   */
  static async clearReportCache(tenantId: string): Promise<void> {
    const pattern = `${this.CACHE_PREFIX}*:${tenantId}*`;
    await RedisService.deletePattern(pattern);
    logger.info(`[ShopReport] Cleared report cache for tenant ${tenantId}`);
  }

  /**
   * 生成趋势数据
   */
  private static generateTrendData(
    dateFrom: Date,
    dateTo: Date,
    granularity: TimeGranularity,
    orders: any[]
  ): Array<{ date: string; sales: number; orders: number }> {
    const trend: Array<{ date: string; sales: number; orders: number }> = [];
    const current = new Date(dateFrom);
    const end = new Date(dateTo);

    while (current <= end) {
      const dateStr = current.toISOString().split('T')[0];
      const dayOrders = orders.filter(o => 
        new Date(o.created_at).toISOString().split('T')[0] === dateStr
      );
      
      trend.push({
        date: dateStr,
        sales: dayOrders.reduce((sum, o) => sum + Number(o.total_amount || 0), 0),
        orders: dayOrders.length,
      });

      current.setDate(current.getDate() + 1);
    }

    return trend;
  }

  /**
   * 生成利润趋势
   */
  private static generateProfitTrend(
    dateFrom: Date,
    dateTo: Date,
    orders: any[]
  ): Array<{ date: string; revenue: number; cost: number; profit: number }> {
    const trend: Array<{ date: string; revenue: number; cost: number; profit: number }> = [];
    const current = new Date(dateFrom);
    const end = new Date(dateTo);

    while (current <= end) {
      const dateStr = current.toISOString().split('T')[0];
      const dayOrders = orders.filter(o => 
        new Date(o.created_at).toISOString().split('T')[0] === dateStr
      );

      const revenue = dayOrders.reduce((sum, o) => sum + Number(o.total_amount || 0), 0);
      const cost = dayOrders.reduce((sum, o) => sum + Number(o.cost_amount || Number(o.total_amount) * 0.7), 0);
      
      trend.push({
        date: dateStr,
        revenue,
        cost,
        profit: revenue - cost,
      });

      current.setDate(current.getDate() + 1);
    }

    return trend;
  }

  /**
   * 生成流量趋势
   */
  private static generateTrafficTrend(
    dateFrom: Date,
    dateTo: Date
  ): Array<{ date: string; views: number; visitors: number }> {
    const trend: Array<{ date: string; views: number; visitors: number }> = [];
    const current = new Date(dateFrom);
    const end = new Date(dateTo);

    while (current <= end) {
      trend.push({
        date: current.toISOString().split('T')[0],
        views: Math.floor(Math.random() * 5000) + 2000,
        visitors: Math.floor(Math.random() * 3500) + 1400,
      });
      current.setDate(current.getDate() + 1);
    }

    return trend;
  }

  /**
   * 生成转化趋势
   */
  private static generateConversionTrend(
    dateFrom: Date,
    dateTo: Date
  ): Array<{ date: string; conversions: number; rate: number }> {
    const trend: Array<{ date: string; conversions: number; rate: number }> = [];
    const current = new Date(dateFrom);
    const end = new Date(dateTo);

    while (current <= end) {
      trend.push({
        date: current.toISOString().split('T')[0],
        conversions: Math.floor(Math.random() * 200) + 50,
        rate: Math.random() * 3 + 2,
      });
      current.setDate(current.getDate() + 1);
    }

    return trend;
  }
}
