import db from '../config/database';
import { logger } from '../utils/logger';
import { v4 as uuidv4 } from 'uuid';

export interface ReturnRecord {
  id: string;
  tenant_id: string;
  shop_id: string;
  task_id?: string;
  trace_id: string;
  order_id: string;
  order_item_id: string;
  product_id: string;
  sku_id: string;
  platform: string;
  platform_product_id: string;
  platform_sku_id: string;
  buyer_id: string;
  return_id: string;
  return_reason: string;
  return_reason_category: string;
  return_quantity: number;
  refund_amount: decimal;
  return_status: 'PENDING' | 'APPROVED' | 'REJECTED' | 'COMPLETED';
  return_type: 'FULL' | 'PARTIAL';
  inspection_result?: string;
  is_accepted: boolean;
  restocking_fee?: decimal;
  return_shipping_fee?: decimal;
  created_at: Date;
  updated_at: Date;
}

export interface SKUReturnMetrics {
  id: string;
  tenant_id: string;
  shop_id: string;
  product_id: string;
  sku_id: string;
  platform: string;
  platform_product_id: string;
  platform_sku_id: string;
  total_orders: number;
  total_returns: number;
  return_rate: decimal;
  return_rate_trend: decimal;
  avg_refund_amount: decimal;
  total_refund_amount: decimal;
  return_by_reason: Record<string, number>;
  return_by_month: Record<string, number>;
  high_risk_threshold: decimal;
  is_high_risk: boolean;
  is_auto_delisted: boolean;
  last_calculated_at: Date;
  calculated_period_start: Date;
  calculated_period_end: Date;
}

export interface ReturnRateThreshold {
  id: string;
  tenant_id: string;
  shop_id?: string;
  platform?: string;
  category?: string;
  threshold_type: 'GLOBAL' | 'PLATFORM' | 'CATEGORY' | 'SKU';
  return_rate_threshold: decimal;
  auto_delist_enabled: boolean;
  delist_duration_hours?: number;
  notification_enabled: boolean;
  notify_emails?: string[];
  created_by: string;
  created_at: Date;
  updated_at: Date;
}

export interface ReturnAnalysis {
  product_id: string;
  sku_id: string;
  return_rate: decimal;
  top_return_reasons: string[];
  customer_sentiment: 'POSITIVE' | 'NEUTRAL' | 'NEGATIVE';
  improvement_priority: 'HIGH' | 'MEDIUM' | 'LOW';
  estimated_impact: string;
  recommendations: string[];
}

export default class ReturnRateDatabaseService {
  static readonly TABLE_NAME = 'cf_return_record';
  static readonly SKU_METRICS_TABLE = 'cf_sku_return_metrics';
  static readonly THRESHOLD_TABLE = 'cf_return_rate_threshold';

  static async initTable(): Promise<void> {
    const hasTable = await db.schema.hasTable(this.TABLE_NAME);
    if (!hasTable) {
      logger.info(`[ReturnRateDatabaseService] Creating ${this.TABLE_NAME} table...`);
      await db.schema.createTable(this.TABLE_NAME, (table) => {
        table.string('id', 36).primary();
        table.string('tenant_id', 64).notNullable().index();
        table.string('shop_id', 64).notNullable().index();
        table.string('task_id', 36);
        table.string('trace_id', 64).notNullable();
        table.string('order_id', 64).notNullable().index();
        table.string('order_item_id', 64).notNullable();
        table.string('product_id', 64).notNullable().index();
        table.string('sku_id', 64).notNullable().index();
        table.string('platform', 64).notNullable().index();
        table.string('platform_product_id', 64).notNullable();
        table.string('platform_sku_id', 64).notNullable();
        table.string('buyer_id', 64).notNullable();
        table.string('return_id', 64).notNullable().unique();
        table.text('return_reason').notNullable();
        table.string('return_reason_category', 64).notNullable();
        table.integer('return_quantity').notNullable();
        table.decimal('refund_amount', 10, 2).notNullable();
        table.enum('return_status', ['PENDING', 'APPROVED', 'REJECTED', 'COMPLETED']).notNullable();
        table.enum('return_type', ['FULL', 'PARTIAL']).notNullable();
        table.text('inspection_result');
        table.boolean('is_accepted').notNullable().defaultTo(false);
        table.decimal('restocking_fee', 10, 2);
        table.decimal('return_shipping_fee', 10, 2);
        table.datetime('created_at').notNullable().defaultTo(db.fn.now());
        table.datetime('updated_at').notNullable().defaultTo(db.fn.now());
        
        table.index(['tenant_id', 'shop_id']);
        table.index(['platform', 'platform_product_id']);
        table.index(['return_status', 'created_at']);
      });
      logger.info(`[ReturnRateDatabaseService] Table ${this.TABLE_NAME} created`);
    }

    const hasMetricsTable = await db.schema.hasTable(this.SKU_METRICS_TABLE);
    if (!hasMetricsTable) {
      logger.info(`[ReturnRateDatabaseService] Creating ${this.SKU_METRICS_TABLE} table...`);
      await db.schema.createTable(this.SKU_METRICS_TABLE, (table) => {
        table.string('id', 36).primary();
        table.string('tenant_id', 64).notNullable().index();
        table.string('shop_id', 64).notNullable().index();
        table.string('product_id', 64).notNullable().index();
        table.string('sku_id', 64).notNullable().index();
        table.string('platform', 64).notNullable().index();
        table.string('platform_product_id', 64).notNullable();
        table.string('platform_sku_id', 64).notNullable();
        table.integer('total_orders').notNullable().defaultTo(0);
        table.integer('total_returns').notNullable().defaultTo(0);
        table.decimal('return_rate', 5, 2).notNullable().defaultTo(0);
        table.decimal('return_rate_trend', 5, 2).notNullable().defaultTo(0);
        table.decimal('avg_refund_amount', 10, 2).notNullable().defaultTo(0);
        table.decimal('total_refund_amount', 10, 2).notNullable().defaultTo(0);
        table.json('return_by_reason').notNullable();
        table.json('return_by_month').notNullable();
        table.decimal('high_risk_threshold', 5, 2).notNullable().defaultTo(30);
        table.boolean('is_high_risk').notNullable().defaultTo(false);
        table.boolean('is_auto_delisted').notNullable().defaultTo(false);
        table.datetime('last_calculated_at').notNullable();
        table.datetime('calculated_period_start').notNullable();
        table.datetime('calculated_period_end').notNullable();
        
        table.index(['tenant_id', 'shop_id', 'platform']);
        table.index(['return_rate', 'is_high_risk']);
        table.index(['is_auto_delisted']);
      });
      logger.info(`[ReturnRateDatabaseService] Table ${this.SKU_METRICS_TABLE} created`);
    }

    const hasThresholdTable = await db.schema.hasTable(this.THRESHOLD_TABLE);
    if (!hasThresholdTable) {
      logger.info(`[ReturnRateDatabaseService] Creating ${this.THRESHOLD_TABLE} table...`);
      await db.schema.createTable(this.THRESHOLD_TABLE, (table) => {
        table.string('id', 36).primary();
        table.string('tenant_id', 64).notNullable().index();
        table.string('shop_id', 64);
        table.string('platform', 64);
        table.string('category', 64);
        table.enum('threshold_type', ['GLOBAL', 'PLATFORM', 'CATEGORY', 'SKU']).notNullable();
        table.decimal('return_rate_threshold', 5, 2).notNullable();
        table.boolean('auto_delist_enabled').notNullable().defaultTo(true);
        table.integer('delist_duration_hours');
        table.boolean('notification_enabled').notNullable().defaultTo(true);
        table.json('notify_emails');
        table.string('created_by', 64).notNullable();
        table.datetime('created_at').notNullable().defaultTo(db.fn.now());
        table.datetime('updated_at').notNullable().defaultTo(db.fn.now());
        
        table.unique(['tenant_id', 'threshold_type', 'platform', 'category']);
      });
      logger.info(`[ReturnRateDatabaseService] Table ${this.THRESHOLD_TABLE} created`);
    }
  }

  static async createReturnRecord(record: Omit<ReturnRecord, 'id' | 'created_at' | 'updated_at'>): Promise<ReturnRecord> {
    const id = uuidv4();
    const now = new Date();
    
    const newRecord: ReturnRecord = {
      ...record,
      id,
      created_at: now,
      updated_at: now
    };

    await db(this.TABLE_NAME).insert(newRecord);
    logger.info(`[ReturnRateDatabaseService] Return record created: id=${id}, orderId=${record.order_id}, traceId=${record.trace_id}`);
    return newRecord;
  }

  static async getReturnRecords(filter: {
    tenant_id?: string;
    shop_id?: string;
    product_id?: string;
    sku_id?: string;
    platform?: string;
    return_status?: string;
    start_date?: Date;
    end_date?: Date;
  }, limit: number = 100, offset: number = 0): Promise<{ records: ReturnRecord[]; total: number }> {
    let query = db(this.TABLE_NAME);

    if (filter.tenant_id) query = query.where({ tenant_id: filter.tenant_id });
    if (filter.shop_id) query = query.where({ shop_id: filter.shop_id });
    if (filter.product_id) query = query.where({ product_id: filter.product_id });
    if (filter.sku_id) query = query.where({ sku_id: filter.sku_id });
    if (filter.platform) query = query.where({ platform: filter.platform });
    if (filter.return_status) query = query.where({ return_status: filter.return_status });
    if (filter.start_date) query = query.where('created_at', '>=', filter.start_date);
    if (filter.end_date) query = query.where('created_at', '<=', filter.end_date);

    const total = await query.count('id as count').first();
    const records = await query.orderBy('created_at', 'desc').limit(limit).offset(offset);

    return {
      records: records as ReturnRecord[],
      total: total ? parseInt(total.count as string) : 0
    };
  }

  static async updateSKUReturnMetrics(tenantId: string, shopId: string, productId: string, skuId: string, platform: string, periodDays: number = 30): Promise<SKUReturnMetrics | null> {
    try {
      const periodEnd = new Date();
      const periodStart = new Date();
      periodStart.setDate(periodStart.getDate() - periodDays);

      const ordersCount = await db('cf_order_item')
        .join('cf_order', 'cf_order.id', '=', 'cf_order_item.order_id')
        .where('cf_order.tenant_id', tenantId)
        .where('cf_order.shop_id', shopId)
        .where('cf_order_item.product_id', productId)
        .where('cf_order.status', 'COMPLETED')
        .where('cf_order.created_at', '>=', periodStart)
        .count('cf_order_item.id as count')
        .first();

      const returnsCount = await db(this.TABLE_NAME)
        .where({ tenant_id: tenantId, shop_id: shopId, product_id: productId, return_status: 'COMPLETED' })
        .where('created_at', '>=', periodStart)
        .count('id as count')
        .first();

      const refundSum = await db(this.TABLE_NAME)
        .where({ tenant_id: tenantId, shop_id: shopId, product_id: productId, return_status: 'COMPLETED' })
        .where('created_at', '>=', periodStart)
        .sum('refund_amount as total')
        .first();

      const returnReasons = await db(this.TABLE_NAME)
        .select('return_reason_category', db.raw('count(*) as count'))
        .where({ tenant_id: tenantId, shop_id: shopId, product_id: productId })
        .where('created_at', '>=', periodStart)
        .groupBy('return_reason_category');

      const byReason: Record<string, number> = {};
      returnReasons.forEach((r: any) => { byReason[r.return_reason_category] = parseInt(r.count); });

      const totalOrders = ordersCount ? parseInt(ordersCount.count as string) : 0;
      const totalReturns = returnsCount ? parseInt(returnsCount.count as string) : 0;
      const returnRate = totalOrders > 0 ? (totalReturns / totalOrders) * 100 : 0;
      const totalRefund = refundSum?.total ? parseFloat(refundSum.total as string) : 0;
      const avgRefund = totalReturns > 0 ? totalRefund / totalReturns : 0;

      const threshold = await this.getThreshold(tenantId, platform, shopId);
      const thresholdValue = threshold?.return_rate_threshold || 30;
      const isHighRisk = returnRate >= thresholdValue;

      const id = uuidv4();
      const existing = await db(this.SKU_METRICS_TABLE)
        .where({ tenant_id: tenantId, shop_id: shopId, product_id: productId, sku_id: skuId })
        .first();

      if (existing) {
        const oldRate = parseFloat(existing.return_rate as string) || 0;
        const trend = returnRate - oldRate;

        await db(this.SKU_METRICS_TABLE)
          .where({ id: existing.id })
          .update({
            total_orders: totalOrders,
            total_returns: totalReturns,
            return_rate: returnRate,
            return_rate_trend: trend,
            avg_refund_amount: avgRefund,
            total_refund_amount: totalRefund,
            return_by_reason: JSON.stringify(byReason),
            is_high_risk: isHighRisk,
            last_calculated_at: new Date(),
            calculated_period_start: periodStart,
            calculated_period_end: periodEnd,
            updated_at: new Date()
          });

        return await db(this.SKU_METRICS_TABLE).where({ id: existing.id }).first() as SKUReturnMetrics;
      } else {
        await db(this.SKU_METRICS_TABLE).insert({
          id,
          tenant_id: tenantId,
          shop_id: shopId,
          product_id: productId,
          sku_id: skuId,
          platform,
          platform_product_id: '',
          platform_sku_id: '',
          total_orders: totalOrders,
          total_returns: totalReturns,
          return_rate: returnRate,
          return_rate_trend: 0,
          avg_refund_amount: avgRefund,
          total_refund_amount: totalRefund,
          return_by_reason: JSON.stringify(byReason),
          return_by_month: JSON.stringify({}),
          high_risk_threshold: thresholdValue,
          is_high_risk: isHighRisk,
          is_auto_delisted: false,
          last_calculated_at: new Date(),
          calculated_period_start: periodStart,
          calculated_period_end: periodEnd
        });

        return await db(this.SKU_METRICS_TABLE).where({ id }).first() as SKUReturnMetrics;
      }
    } catch (error) {
      logger.error(`[ReturnRateDatabaseService] Failed to update SKU return metrics: ${error}`);
      return null;
    }
  }

  static async getHighRiskSKUs(tenantId: string, shopId?: string, limit: number = 100): Promise<SKUReturnMetrics[]> {
    let query = db(this.SKU_METRICS_TABLE)
      .where({ tenant_id: tenantId, is_high_risk: true })
      .orderBy('return_rate', 'desc')
      .limit(limit);

    if (shopId) query = query.where({ shop_id: shopId });
    return query as SKUReturnMetrics[];
  }

  static async getAutoDelistSKUs(tenantId: string): Promise<SKUReturnMetrics[]> {
    return db(this.SKU_METRICS_TABLE)
      .where({ tenant_id: tenantId, is_high_risk: true, is_auto_delisted: false }) as SKUReturnMetrics[];
  }

  static async markSKUDelisted(id: string, delisted: boolean): Promise<boolean> {
    const result = await db(this.SKU_METRICS_TABLE)
      .where({ id })
      .update({ is_auto_delisted: delisted, updated_at: new Date() });
    return result > 0;
  }

  static async setThreshold(threshold: Omit<ReturnRateThreshold, 'id' | 'created_at' | 'updated_at'>): Promise<ReturnRateThreshold> {
    const id = uuidv4();
    const now = new Date();

    const existing = await db(this.THRESHOLD_TABLE)
      .where({ tenant_id: threshold.tenant_id, threshold_type: threshold.threshold_type })
      .whereNull('shop_id')
      .first();

    if (existing) {
      await db(this.THRESHOLD_TABLE)
        .where({ id: existing.id })
        .update({ ...threshold, updated_at: now });
      return { ...threshold, id: existing.id, created_at: existing.created_at, updated_at: now } as ReturnRateThreshold;
    }

    await db(this.THRESHOLD_TABLE).insert({ ...threshold, id, created_at: now, updated_at: now });
    return { ...threshold, id, created_at: now, updated_at: now } as ReturnRateThreshold;
  }

  static async getThreshold(tenantId: string, platform?: string, shopId?: string): Promise<ReturnRateThreshold | null> {
    let threshold = await db(this.THRESHOLD_TABLE)
      .where({ tenant_id: tenantId, threshold_type: 'GLOBAL' })
      .first();

    if (!threshold && platform) {
      threshold = await db(this.THRESHOLD_TABLE)
        .where({ tenant_id: tenantId, threshold_type: 'PLATFORM', platform })
        .first();
    }

    return threshold as ReturnRateThreshold || null;
  }

  static async getAllThresholds(tenantId: string): Promise<ReturnRateThreshold[]> {
    return db(this.THRESHOLD_TABLE).where({ tenant_id: tenantId }) as ReturnRateThreshold[];
  }

  static async deleteThreshold(id: string): Promise<boolean> {
    const result = await db(this.THRESHOLD_TABLE).where({ id }).del();
    return result > 0;
  }

  static async getReturnRateTrend(tenantId: string, productId: string, days: number = 90): Promise<{ date: string; rate: number }[]> {
    const startDate = new Date();
    startDate.setDate(startDate.getDate() - days);

    const returns = await db(this.TABLE_NAME)
      .select(db.raw('DATE(created_at) as date'), db.raw('count(*) as count'))
      .where({ tenant_id: tenantId, product_id: productId, return_status: 'COMPLETED' })
      .where('created_at', '>=', startDate)
      .groupBy(db.raw('DATE(created_at)'))
      .orderBy('date');

    const result: { date: string; rate: number }[] = [];
    for (let i = days; i >= 0; i--) {
      const d = new Date();
      d.setDate(d.getDate() - i);
      const dateStr = d.toISOString().split('T')[0];
      const found = returns.find((r: any) => r.date === dateStr);
      result.push({ date: dateStr, rate: found ? parseInt(found.count) : 0 });
    }
    return result;
  }
}

type decimal = number;
