import { v4 as uuidv4 } from 'uuid';
import db from '../config/database';
import { logger } from '../utils/logger';
import { PricingService, PricingParams, ProfitSnapshot } from './PricingService';
import ExchangeRateService from './ExchangeRateService';
import { RiskLevel, PriceComparisonStatus, BusinessType } from '../types/enums';

export interface PriceComparison {
  id: string;
  tenant_id: string;
  product_id: string;
  product_name: string;
  source_platform: string;
  source_price: number;
  source_currency: string;
  target_platform: string;
  target_price: number;
  target_currency: string;
  price_difference: number;
  price_difference_percent: number;
  exchange_rate: number;
  profit_snapshot: ProfitSnapshot | null;
  risk_level: RiskLevel;
  opportunity_score: number;
  status: PriceComparisonStatus;
  created_at: Date;
  updated_at: Date;
}

export interface PriceComparisonInput {
  tenantId: string;
  productId: string;
  productName: string;
  sourcePlatform: string;
  sourcePrice: number;
  sourceCurrency: string;
  targetPlatform: string;
  targetPrice: number;
  targetCurrency: string;
  logisticsCost?: number;
  adBudget?: number;
  isB2B?: boolean;
}

export interface PlatformPrice {
  platform: string;
  price: number;
  currency: string;
  url?: string;
  inStock?: boolean;
  lastUpdated: Date;
}

export interface ComparisonResult {
  productId: string;
  productName: string;
  sourcePrice: PlatformPrice;
  targetPrices: PlatformPrice[];
  comparisons: PriceComparison[];
  bestOpportunity: PriceComparison | null;
  recommendation: string;
}

export class PriceComparisonService {
  private static instance: PriceComparisonService;
  private static readonly TABLE_NAME = 'cf_price_comparisons';

  private constructor() {}

  static getInstance(): PriceComparisonService {
    if (!PriceComparisonService.instance) {
      PriceComparisonService.instance = new PriceComparisonService();
    }
    return PriceComparisonService.instance;
  }

  async comparePrices(input: PriceComparisonInput): Promise<PriceComparison> {
    const {
      tenantId,
      productId,
      productName,
      sourcePlatform,
      sourcePrice,
      sourceCurrency,
      targetPlatform,
      targetPrice,
      targetCurrency,
      logisticsCost = 5.0,
      adBudget = 2.0,
      isB2B = false
    } = input;

    const exchangeRate = await ExchangeRateService.getRate(sourceCurrency, targetCurrency);
    const priceDifference = targetPrice - sourcePrice * exchangeRate;
    const priceDifferencePercent = (priceDifference / (sourcePrice * exchangeRate)) * 100;

    let profitSnapshot: ProfitSnapshot | null = null;
    let riskLevel: PriceComparison['riskLevel'] = 'LOW';
    let opportunityScore = 0;

    if (priceDifference > 0) {
      const pricingParams: PricingParams = {
        sellingPrice: targetPrice,
        purchasePrice: sourcePrice * exchangeRate,
        platform: targetPlatform,
        countryCode: 'US',
        logisticsCost,
        adBudget,
        isB2B
      };

      profitSnapshot = await PricingService.calculateNetProfit(pricingParams);

      const riskCheck = PricingService.checkRisk(profitSnapshot, isB2B);
      switch (riskCheck.level) {
        case 'BLOCK':
          riskLevel = 'BLOCK';
          break;
        case 'WARN':
          riskLevel = 'HIGH';
          break;
        default:
          riskLevel = profitSnapshot.profitRate >= 0.25 ? 'LOW' : 'MEDIUM';
      }

      opportunityScore = PricingService.calculateOpportunityScore(profitSnapshot, {
        priceDiffPercent: priceDifferencePercent
      });
    } else {
      riskLevel = 'BLOCK';
      opportunityScore = 0;
    }

    const comparison: PriceComparison = {
      id: uuidv4(),
      tenant_id: tenantId,
      product_id: productId,
      product_name: productName,
      source_platform: sourcePlatform,
      source_price: sourcePrice,
      source_currency: sourceCurrency,
      target_platform: targetPlatform,
      target_price: targetPrice,
      target_currency: targetCurrency,
      price_difference: priceDifference,
      price_difference_percent: priceDifferencePercent,
      exchange_rate: exchangeRate,
      profit_snapshot: profitSnapshot,
      risk_level: riskLevel,
      opportunity_score: opportunityScore,
      status: 'ACTIVE',
      created_at: new Date(),
      updated_at: new Date()
    };

    await this.saveComparison(comparison);

    logger.info(`[PriceComparisonService] Created comparison for product ${productId}: ${sourcePlatform} -> ${targetPlatform}, Score: ${opportunityScore}`);

    return comparison;
  }

  async batchComparePrices(
    tenantId: string,
    productId: string,
    productName: string,
    sourcePrice: PlatformPrice,
    targetPrices: PlatformPrice[],
    options?: {
      logisticsCost?: number;
      adBudget?: number;
      isB2B?: boolean;
    }
  ): Promise<ComparisonResult> {
    const comparisons: PriceComparison[] = [];

    for (const targetPrice of targetPrices) {
      const comparison = await this.comparePrices({
        tenantId,
        productId,
        productName,
        sourcePlatform: sourcePrice.platform,
        sourcePrice: sourcePrice.price,
        sourceCurrency: sourcePrice.currency,
        targetPlatform: targetPrice.platform,
        targetPrice: targetPrice.price,
        targetCurrency: targetPrice.currency,
        logisticsCost: options?.logisticsCost,
        adBudget: options?.adBudget,
        isB2B: options?.isB2B
      });
      comparisons.push(comparison);
    }

    const activeComparisons = comparisons.filter(c => c.status === 'ACTIVE' && c.risk_level !== 'BLOCK');
    const bestOpportunity = activeComparisons.length > 0
      ? activeComparisons.reduce((best, current) =>
          current.opportunity_score > best.opportunity_score ? current : best
        )
      : null;

    const recommendation = this.generateRecommendation(bestOpportunity, comparisons);

    return {
      productId,
      productName,
      sourcePrice,
      targetPrices,
      comparisons,
      bestOpportunity,
      recommendation
    };
  }

  async getComparisonsByProduct(tenantId: string, productId: string): Promise<PriceComparison[]> {
    const comparisons = await db(PriceComparisonService.TABLE_NAME)
      .where('tenant_id', tenantId)
      .where('product_id', productId)
      .orderBy('opportunity_score', 'desc');

    return comparisons.map(this.mapComparisonFromDb);
  }

  async getActiveOpportunities(
    tenantId: string,
    options?: {
      minScore?: number;
      maxRiskLevel?: string;
      platform?: string;
      limit?: number;
    }
  ): Promise<PriceComparison[]> {
    let query = db(PriceComparisonService.TABLE_NAME)
      .where('tenant_id', tenantId)
      .where('status', 'ACTIVE')
      .where('risk_level', '!=', 'BLOCK');

    if (options?.minScore) {
      query = query.where('opportunity_score', '>=', options.minScore);
    }

    if (options?.maxRiskLevel) {
      const riskLevels = ['LOW', 'MEDIUM', 'HIGH'];
      const maxIndex = riskLevels.indexOf(options.maxRiskLevel);
      const allowedLevels = riskLevels.slice(0, maxIndex + 1);
      query = query.whereIn('risk_level', allowedLevels);
    }

    if (options?.platform) {
      query = query.where('target_platform', options.platform);
    }

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

    if (options?.limit) {
      query = query.limit(options.limit);
    }

    const comparisons = await query;
    return comparisons.map(this.mapComparisonFromDb);
  }

  async getOpportunityStats(tenantId: string): Promise<{
    totalOpportunities: number;
    activeOpportunities: number;
    avgOpportunityScore: number;
    avgProfitRate: number;
    avgROI: number;
    byPlatform: Record<string, { count: number; avgScore: number }>;
    byRiskLevel: Record<string, number>;
  }> {
    const comparisons = await db(PriceComparisonService.TABLE_NAME)
      .where('tenant_id', tenantId);

    const activeComparisons = comparisons.filter(c => c.status === 'ACTIVE');
    const validComparisons = activeComparisons.filter(c => c.profit_snapshot);

    const byPlatform: Record<string, { count: number; avgScore: number }> = {};
    const byRiskLevel: Record<string, number> = {};

    for (const comp of activeComparisons) {
      const platform = comp.target_platform;
      if (!byPlatform[platform]) {
        byPlatform[platform] = { count: 0, avgScore: 0 };
      }
      byPlatform[platform].count++;
      byPlatform[platform].avgScore += comp.opportunity_score;

      const risk = comp.risk_level;
      byRiskLevel[risk] = (byRiskLevel[risk] || 0) + 1;
    }

    for (const platform in byPlatform) {
      byPlatform[platform].avgScore /= byPlatform[platform].count;
    }

    return {
      totalOpportunities: comparisons.length,
      activeOpportunities: activeComparisons.length,
      avgOpportunityScore: activeComparisons.length > 0
        ? activeComparisons.reduce((sum, c) => sum + c.opportunity_score, 0) / activeComparisons.length
        : 0,
      avgProfitRate: validComparisons.length > 0
        ? validComparisons.reduce((sum, c) => sum + (JSON.parse(c.profit_snapshot as any).profitRate || 0), 0) / validComparisons.length
        : 0,
      avgROI: validComparisons.length > 0
        ? validComparisons.reduce((sum, c) => sum + (JSON.parse(c.profit_snapshot as any).roi || 0), 0) / validComparisons.length
        : 0,
      byPlatform,
      byRiskLevel
    };
  }

  async markAsExecuted(comparisonId: string): Promise<void> {
    await db(PriceComparisonService.TABLE_NAME)
      .where('id', comparisonId)
      .update({
        status: 'EXECUTED',
        updated_at: new Date()
      });

    logger.info(`[PriceComparisonService] Marked comparison ${comparisonId} as executed`);
  }

  async markAsExpired(comparisonId: string): Promise<void> {
    await db(PriceComparisonService.TABLE_NAME)
      .where('id', comparisonId)
      .update({
        status: 'EXPIRED',
        updated_at: new Date()
      });

    logger.info(`[PriceComparisonService] Marked comparison ${comparisonId} as expired`);
  }

  async cleanupExpiredComparisons(hoursOld: number = 24): Promise<number> {
    const cutoffTime = new Date(Date.now() - hoursOld * 60 * 60 * 1000);

    const updated = await db(PriceComparisonService.TABLE_NAME)
      .where('status', 'ACTIVE')
      .where('updated_at', '<', cutoffTime)
      .update({
        status: 'EXPIRED',
        updated_at: new Date()
      });

    logger.info(`[PriceComparisonService] Cleaned up ${updated} expired comparisons`);
    return updated;
  }

  private async saveComparison(comparison: PriceComparison): Promise<void> {
    await db(PriceComparisonService.TABLE_NAME).insert({
      id: comparison.id,
      tenant_id: comparison.tenant_id,
      product_id: comparison.product_id,
      product_name: comparison.product_name,
      source_platform: comparison.source_platform,
      source_price: comparison.source_price,
      source_currency: comparison.source_currency,
      target_platform: comparison.target_platform,
      target_price: comparison.target_price,
      target_currency: comparison.target_currency,
      price_difference: comparison.price_difference,
      price_difference_percent: comparison.price_difference_percent,
      exchange_rate: comparison.exchange_rate,
      profit_snapshot: comparison.profit_snapshot ? JSON.stringify(comparison.profit_snapshot) : null,
      risk_level: comparison.risk_level,
      opportunity_score: comparison.opportunity_score,
      status: comparison.status,
      created_at: comparison.created_at,
      updated_at: comparison.updated_at
    });
  }

  private generateRecommendation(bestOpportunity: PriceComparison | null, comparisons: PriceComparison[]): string {
    if (!bestOpportunity) {
      return 'No profitable arbitrage opportunities found at this time.';
    }

    const profitRate = bestOpportunity.profit_snapshot?.profitRate || 0;
    const roi = bestOpportunity.profit_snapshot?.roi || 0;

    if (profitRate > 0.3 && roi > 0.5) {
      return `Excellent opportunity! ${bestOpportunity.target_platform} offers ${(profitRate * 100).toFixed(1)}% profit margin with ${(roi * 100).toFixed(1)}% ROI. Consider immediate execution.`;
    } else if (profitRate > 0.2 && roi > 0.3) {
      return `Good opportunity on ${bestOpportunity.target_platform}. ${(profitRate * 100).toFixed(1)}% profit margin. Recommended for execution.`;
    } else if (profitRate > 0.15) {
      return `Moderate opportunity on ${bestOpportunity.target_platform}. Monitor price trends before execution.`;
    } else {
      return `Low margin opportunity. Consider waiting for better prices or negotiating lower sourcing costs.`;
    }
  }

  private mapComparisonFromDb(row: any): PriceComparison {
    return {
      id: row.id,
      tenant_id: row.tenant_id,
      product_id: row.product_id,
      product_name: row.product_name,
      source_platform: row.source_platform,
      source_price: parseFloat(row.source_price),
      source_currency: row.source_currency,
      target_platform: row.target_platform,
      target_price: parseFloat(row.target_price),
      target_currency: row.target_currency,
      price_difference: parseFloat(row.price_difference),
      price_difference_percent: parseFloat(row.price_difference_percent),
      exchange_rate: parseFloat(row.exchange_rate),
      profit_snapshot: row.profit_snapshot ? (typeof row.profit_snapshot === 'string' ? JSON.parse(row.profit_snapshot) : row.profit_snapshot) : null,
      risk_level: row.risk_level,
      opportunity_score: row.opportunity_score,
      status: row.status,
      created_at: row.created_at,
      updated_at: row.updated_at
    };
  }
}

export default PriceComparisonService.getInstance();
