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

interface PricingRecommendation {
  recommendationId: string;
  tenantId: string;
  productId: string;
  platform: string;
  currentPrice: number;
  recommendedPrice: number;
  priceChange: number;
  priceChangePercent: number;
  strategy: 'MAXIMIZE_PROFIT' | 'MAXIMIZE_VOLUME' | 'COMPETITIVE' | 'PENETRATION' | 'PREMIUM';
  confidence: number;
  reasoning: string[];
  impact: {
    expectedMargin: number;
    expectedVolume: number;
    expectedRevenue: number;
    competitorPosition: string;
  };
  validUntil: Date;
  createdAt: Date;
}

interface PricingFactors {
  costOfGoods: number;
  currentPrice: number;
  competitorPrices: number[];
  avgCompetitorPrice: number;
  minCompetitorPrice: number;
  maxCompetitorPrice: number;
  demandScore: number;
  seasonalityFactor: number;
  inventoryLevel: number;
  salesVelocity: number;
  categoryTrend: number;
}

interface PricingStrategy {
  name: string;
  description: string;
  calculatePrice: (factors: PricingFactors) => number;
  applicableConditions: (factors: PricingFactors) => boolean;
}

interface PriceSimulation {
  price: number;
  margin: number;
  estimatedVolume: number;
  estimatedRevenue: number;
  competitorPosition: string;
  riskLevel: 'LOW' | 'MEDIUM' | 'HIGH';
}

export class SmartPricingService {
  private static MIN_PROFIT_MARGIN_TOC = 0.20;
  private static MIN_PROFIT_MARGIN_TOB = 0.15;
  private static MAX_PRICE_CHANGE = 0.30;

  private static STRATEGIES: PricingStrategy[] = [
    {
      name: 'MAXIMIZE_PROFIT',
      description: 'Optimize for highest profit margin while maintaining reasonable volume',
      calculatePrice: (factors) => {
        const basePrice = factors.costOfGoods * (1 + 0.35);
        const competitorCeiling = factors.maxCompetitorPrice * 0.95;
        return Math.min(basePrice, competitorCeiling);
      },
      applicableConditions: (factors) => factors.demandScore >= 70
    },
    {
      name: 'MAXIMIZE_VOLUME',
      description: 'Lower price to maximize sales volume and market share',
      calculatePrice: (factors) => {
        const basePrice = factors.costOfGoods * (1 + 0.18);
        const competitorFloor = factors.minCompetitorPrice * 0.98;
        return Math.max(basePrice, competitorFloor);
      },
      applicableConditions: (factors) => factors.inventoryLevel > 100 && factors.demandScore >= 50
    },
    {
      name: 'COMPETITIVE',
      description: 'Price at market average to remain competitive',
      calculatePrice: (factors) => {
        return factors.avgCompetitorPrice * 0.98;
      },
      applicableConditions: (factors) => factors.competitorPrices.length > 0
    },
    {
      name: 'PENETRATION',
      description: 'Aggressive pricing to gain market entry',
      calculatePrice: (factors) => {
        const basePrice = factors.costOfGoods * (1 + 0.12);
        const competitorFloor = factors.minCompetitorPrice * 0.90;
        return Math.max(basePrice, competitorFloor);
      },
      applicableConditions: (factors) => factors.salesVelocity < 10
    },
    {
      name: 'PREMIUM',
      description: 'Premium pricing for differentiated products',
      calculatePrice: (factors) => {
        const basePrice = factors.costOfGoods * (1 + 0.50);
        const competitorCeiling = factors.maxCompetitorPrice * 1.10;
        return Math.min(basePrice, competitorCeiling);
      },
      applicableConditions: (factors) => factors.demandScore >= 80 && factors.competitorPrices.length < 5
    }
  ];

  private static generateId(prefix: string): string {
    return `${prefix}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }

  static async generatePricingRecommendation(params: {
    tenantId: string;
    productId: string;
    platform: string;
    strategy?: PricingStrategy['name'];
    businessType?: 'TOC' | 'TOB';
  }): Promise<PricingRecommendation> {
    const { tenantId, productId, platform, strategy, businessType = 'TOC' } = params;

    logger.info('[SmartPricingService] Generating pricing recommendation', {
      tenantId,
      productId,
      platform,
      strategy
    });

    const factors = await this.gatherPricingFactors(tenantId, productId, platform);
    const selectedStrategy = (strategy || this.selectBestStrategy(factors)) as PricingRecommendation['strategy'];
    const recommendedPrice = this.calculateRecommendedPrice(factors, selectedStrategy);
    const validatedPrice = this.validatePrice(recommendedPrice, factors, businessType);

    const currentPrice = factors.currentPrice;
    const priceChange = validatedPrice - currentPrice;
    const priceChangePercent = (priceChange / currentPrice) * 100;

    const impact = await this.calculateImpact(validatedPrice, factors, platform);
    const reasoning = this.generateReasoning(factors, validatedPrice, selectedStrategy);
    const confidence = this.calculateConfidence(factors);

    const recommendation: PricingRecommendation = {
      recommendationId: this.generateId('price_rec'),
      tenantId,
      productId,
      platform,
      currentPrice,
      recommendedPrice: validatedPrice,
      priceChange,
      priceChangePercent,
      strategy: selectedStrategy,
      confidence,
      reasoning,
      impact,
      validUntil: new Date(Date.now() + 24 * 60 * 60 * 1000),
      createdAt: new Date()
    };

    await this.saveRecommendation(recommendation);

    return recommendation;
  }

  static async simulatePricing(params: {
    tenantId: string;
    productId: string;
    platform: string;
    priceRange?: { min: number; max: number };
    steps?: number;
  }): Promise<PriceSimulation[]> {
    const { tenantId, productId, platform, priceRange, steps = 10 } = params;

    logger.info('[SmartPricingService] Simulating pricing', {
      tenantId,
      productId,
      platform
    });

    const factors = await this.gatherPricingFactors(tenantId, productId, platform);
    const minPrice = priceRange?.min || factors.costOfGoods * 1.10;
    const maxPrice = priceRange?.max || factors.maxCompetitorPrice * 1.20;
    const stepSize = (maxPrice - minPrice) / steps;

    const simulations: PriceSimulation[] = [];

    for (let i = 0; i <= steps; i++) {
      const price = minPrice + (stepSize * i);
      const simulation = await this.simulateSinglePrice(price, factors);
      simulations.push(simulation);
    }

    return simulations;
  }

  static async applyRecommendation(params: {
    recommendationId: string;
    tenantId: string;
    approvedBy: string;
  }): Promise<{
    success: boolean;
    newPrice: number;
    listingId: string;
  }> {
    const { recommendationId, tenantId, approvedBy } = params;

    logger.info('[SmartPricingService] Applying pricing recommendation', {
      recommendationId,
      tenantId,
      approvedBy
    });

    const recommendation = await this.getRecommendation(recommendationId, tenantId);

    if (!recommendation) {
      throw new Error('Recommendation not found');
    }

    if (recommendation.validUntil < new Date()) {
      throw new Error('Recommendation has expired');
    }

    const listing = await db('cf_listing')
      .where({
        tenant_id: tenantId,
        product_id: recommendation.productId,
        platform: recommendation.platform
      })
      .first();

    if (!listing) {
      throw new Error('Listing not found');
    }

    await db('cf_listing')
      .where({ id: listing.id })
      .update({
        price: recommendation.recommendedPrice,
        previous_price: recommendation.currentPrice,
        price_updated_at: new Date(),
        updated_at: new Date()
      });

    await db('cf_price_change_log').insert({
      id: this.generateId('price_log'),
      tenant_id: tenantId,
      product_id: recommendation.productId,
      platform: recommendation.platform,
      old_price: recommendation.currentPrice,
      new_price: recommendation.recommendedPrice,
      change_reason: `AI Recommendation - ${recommendation.strategy}`,
      approved_by: approvedBy,
      created_at: new Date()
    });

    await db('cf_pricing_recommendation')
      .where({ id: recommendationId })
      .update({
        status: 'APPLIED',
        applied_at: new Date(),
        applied_by: approvedBy
      });

    return {
      success: true,
      newPrice: recommendation.recommendedPrice,
      listingId: listing.id
    };
  }

  static async getActiveRecommendations(params: {
    tenantId: string;
    productId?: string;
    platform?: string;
    limit?: number;
  }): Promise<PricingRecommendation[]> {
    const { tenantId, productId, platform, limit = 20 } = params;

    let query = db('cf_pricing_recommendation')
      .where({ tenant_id: tenantId })
      .where('status', 'PENDING')
      .where('valid_until', '>', new Date())
      .orderBy('created_at', 'desc')
      .limit(limit);

    if (productId) {
      query = query.where({ product_id: productId });
    }

    if (platform) {
      query = query.where({ platform });
    }

    const results = await query;

    return results.map(this.mapToRecommendation);
  }

  static async batchGenerateRecommendations(params: {
    tenantId: string;
    productIds: string[];
    platform: string;
    strategy?: PricingStrategy['name'];
  }): Promise<PricingRecommendation[]> {
    const { tenantId, productIds, platform, strategy } = params;

    logger.info('[SmartPricingService] Batch generating recommendations', {
      tenantId,
      count: productIds.length,
      platform
    });

    const recommendations: PricingRecommendation[] = [];

    for (const productId of productIds) {
      try {
        const recommendation = await this.generatePricingRecommendation({
          tenantId,
          productId,
          platform,
          strategy
        });
        recommendations.push(recommendation);
      } catch (error: any) {
        logger.error('[SmartPricingService] Failed to generate recommendation', {
          productId,
          error: error.message
        });
      }
    }

    return recommendations;
  }

  static async getPriceHistory(params: {
    tenantId: string;
    productId: string;
    platform: string;
    limit?: number;
  }): Promise<Array<{
    price: number;
    changedAt: Date;
    reason: string;
    approvedBy?: string;
  }>> {
    const { tenantId, productId, platform, limit = 30 } = params;

    const history = await db('cf_price_change_log')
      .where({
        tenant_id: tenantId,
        product_id: productId,
        platform
      })
      .orderBy('created_at', 'desc')
      .limit(limit);

    return history.map(h => ({
      price: parseFloat(h.new_price),
      changedAt: h.created_at,
      reason: h.change_reason,
      approvedBy: h.approved_by
    }));
  }

  private static async gatherPricingFactors(
    tenantId: string,
    productId: string,
    platform: string
  ): Promise<PricingFactors> {
    const product = await db('cf_product')
      .where({ id: productId, tenant_id: tenantId })
      .first();

    const listing = await db('cf_listing')
      .where({ tenant_id: tenantId, product_id: productId, platform })
      .first();

    const inventory = await db('cf_inventory')
      .where({ tenant_id: tenantId, sku_id: productId })
      .first();

    const competitorAnalysis = await CompetitorPriceMonitor.getCompetitorAnalysis({
      tenantId,
      productId,
      platform
    });

    const scoreResult = await ProductScoringService.calculateScore({
      productId,
      tenantId,
      factors: {
        salesVelocity: listing?.sales_count,
        reviewCount: product?.review_count,
        pricePoint: product?.price
      }
    });

    return {
      costOfGoods: product?.cost_price || product?.price * 0.5,
      currentPrice: listing?.price || product?.price || 0,
      competitorPrices: competitorAnalysis.competitors.map(c => c.price),
      avgCompetitorPrice: competitorAnalysis.avgCompetitorPrice,
      minCompetitorPrice: competitorAnalysis.minCompetitorPrice,
      maxCompetitorPrice: competitorAnalysis.maxCompetitorPrice,
      demandScore: scoreResult.dimensions.marketDemand,
      seasonalityFactor: 1.0,
      inventoryLevel: inventory?.available_qty || 0,
      salesVelocity: listing?.sales_count || 0,
      categoryTrend: scoreResult.dimensions.trendScore
    };
  }

  private static selectBestStrategy(factors: PricingFactors): PricingStrategy['name'] {
    const applicableStrategies = this.STRATEGIES.filter(s => s.applicableConditions(factors));

    if (applicableStrategies.length === 0) {
      return 'COMPETITIVE';
    }

    if (factors.demandScore >= 80 && factors.competitorPrices.length < 5) {
      return 'PREMIUM';
    }

    if (factors.inventoryLevel > 100 && factors.demandScore >= 50) {
      return 'MAXIMIZE_VOLUME';
    }

    if (factors.salesVelocity < 10) {
      return 'PENETRATION';
    }

    if (factors.demandScore >= 70) {
      return 'MAXIMIZE_PROFIT';
    }

    return 'COMPETITIVE';
  }

  private static calculateRecommendedPrice(
    factors: PricingFactors,
    strategy: PricingStrategy['name']
  ): number {
    const strategyConfig = this.STRATEGIES.find(s => s.name === strategy);

    if (!strategyConfig) {
      return factors.avgCompetitorPrice || factors.currentPrice;
    }

    return strategyConfig.calculatePrice(factors);
  }

  private static validatePrice(
    price: number,
    factors: PricingFactors,
    businessType: 'TOC' | 'TOB'
  ): number {
    const minMargin = businessType === 'TOC' 
      ? this.MIN_PROFIT_MARGIN_TOC 
      : this.MIN_PROFIT_MARGIN_TOB;

    const minPrice = factors.costOfGoods * (1 + minMargin);

    if (price < minPrice) {
      logger.warn('[SmartPricingService] Price below minimum margin, adjusting', {
        requestedPrice: price,
        minimumPrice: minPrice
      });
      return minPrice;
    }

    const maxChange = factors.currentPrice * this.MAX_PRICE_CHANGE;
    const upperBound = factors.currentPrice + maxChange;
    const lowerBound = factors.currentPrice - maxChange;

    if (price > upperBound) {
      return upperBound;
    }

    if (price < lowerBound) {
      return lowerBound;
    }

    return Math.round(price * 100) / 100;
  }

  private static async calculateImpact(
    price: number,
    factors: PricingFactors,
    platform: string
  ): Promise<PricingRecommendation['impact']> {
    const margin = (price - factors.costOfGoods) / price;

    let volumeMultiplier = 1.0;
    if (price < factors.avgCompetitorPrice * 0.95) {
      volumeMultiplier = 1.2;
    } else if (price > factors.avgCompetitorPrice * 1.05) {
      volumeMultiplier = 0.8;
    }

    const estimatedVolume = Math.round(factors.salesVelocity * volumeMultiplier * 30);
    const estimatedRevenue = estimatedVolume * price;

    let competitorPosition = 'AVERAGE';
    if (price <= factors.minCompetitorPrice) {
      competitorPosition = 'LOWEST';
    } else if (price >= factors.maxCompetitorPrice) {
      competitorPosition = 'HIGHEST';
    } else if (price < factors.avgCompetitorPrice) {
      competitorPosition = 'BELOW_AVG';
    } else if (price > factors.avgCompetitorPrice) {
      competitorPosition = 'ABOVE_AVG';
    }

    return {
      expectedMargin: Math.round(margin * 10000) / 100,
      expectedVolume: estimatedVolume,
      expectedRevenue: Math.round(estimatedRevenue * 100) / 100,
      competitorPosition
    };
  }

  private static generateReasoning(
    factors: PricingFactors,
    recommendedPrice: number,
    strategy: PricingStrategy['name']
  ): string[] {
    const reasons: string[] = [];

    reasons.push(`Selected strategy: ${strategy}`);

    if (factors.competitorPrices.length > 0) {
      const priceVsAvg = ((recommendedPrice / factors.avgCompetitorPrice) - 1) * 100;
      if (priceVsAvg < -5) {
        reasons.push(`Price is ${Math.abs(priceVsAvg).toFixed(1)}% below market average for competitive advantage`);
      } else if (priceVsAvg > 5) {
        reasons.push(`Price is ${priceVsAvg.toFixed(1)}% above market average reflecting product value`);
      } else {
        reasons.push('Price is aligned with market average');
      }
    }

    const margin = ((recommendedPrice - factors.costOfGoods) / recommendedPrice) * 100;
    reasons.push(`Expected profit margin: ${margin.toFixed(1)}%`);

    if (factors.demandScore >= 70) {
      reasons.push('High demand score supports current pricing strategy');
    } else if (factors.demandScore < 40) {
      reasons.push('Low demand score suggests competitive pricing needed');
    }

    if (factors.inventoryLevel > 100) {
      reasons.push('High inventory level - consider volume-focused pricing');
    } else if (factors.inventoryLevel < 20) {
      reasons.push('Low inventory - consider margin-focused pricing');
    }

    return reasons;
  }

  private static calculateConfidence(factors: PricingFactors): number {
    let confidence = 50;

    if (factors.competitorPrices.length >= 3) confidence += 20;
    else if (factors.competitorPrices.length >= 1) confidence += 10;

    if (factors.demandScore >= 70) confidence += 15;
    else if (factors.demandScore >= 50) confidence += 10;

    if (factors.salesVelocity > 0) confidence += 10;
    if (factors.costOfGoods > 0) confidence += 5;

    return Math.min(100, confidence);
  }

  private static async simulateSinglePrice(
    price: number,
    factors: PricingFactors
  ): Promise<PriceSimulation> {
    const margin = (price - factors.costOfGoods) / price;

    let volumeMultiplier = 1.0;
    if (factors.avgCompetitorPrice > 0) {
      const priceRatio = price / factors.avgCompetitorPrice;
      if (priceRatio < 0.9) volumeMultiplier = 1.3;
      else if (priceRatio < 1.0) volumeMultiplier = 1.1;
      else if (priceRatio > 1.1) volumeMultiplier = 0.7;
      else if (priceRatio > 1.0) volumeMultiplier = 0.9;
    }

    const estimatedVolume = Math.round(factors.salesVelocity * volumeMultiplier * 30);
    const estimatedRevenue = estimatedVolume * price;

    let competitorPosition = 'AVERAGE';
    if (factors.competitorPrices.length > 0) {
      if (price <= factors.minCompetitorPrice) competitorPosition = 'LOWEST';
      else if (price >= factors.maxCompetitorPrice) competitorPosition = 'HIGHEST';
      else if (price < factors.avgCompetitorPrice) competitorPosition = 'BELOW_AVG';
      else if (price > factors.avgCompetitorPrice) competitorPosition = 'ABOVE_AVG';
    }

    let riskLevel: 'LOW' | 'MEDIUM' | 'HIGH' = 'LOW';
    if (margin < 0.15) riskLevel = 'HIGH';
    else if (margin < 0.20) riskLevel = 'MEDIUM';

    return {
      price: Math.round(price * 100) / 100,
      margin: Math.round(margin * 10000) / 100,
      estimatedVolume,
      estimatedRevenue: Math.round(estimatedRevenue * 100) / 100,
      competitorPosition,
      riskLevel
    };
  }

  private static async saveRecommendation(recommendation: PricingRecommendation): Promise<void> {
    try {
      await db('cf_pricing_recommendation').insert({
        id: recommendation.recommendationId,
        tenant_id: recommendation.tenantId,
        product_id: recommendation.productId,
        platform: recommendation.platform,
        current_price: recommendation.currentPrice,
        recommended_price: recommendation.recommendedPrice,
        price_change: recommendation.priceChange,
        price_change_percent: recommendation.priceChangePercent,
        strategy: recommendation.strategy,
        confidence: recommendation.confidence,
        reasoning: JSON.stringify(recommendation.reasoning),
        impact: JSON.stringify(recommendation.impact),
        valid_until: recommendation.validUntil,
        status: 'PENDING',
        created_at: recommendation.createdAt
      });
    } catch (error: any) {
      logger.error('[SmartPricingService] Failed to save recommendation', {
        recommendationId: recommendation.recommendationId,
        error: error.message
      });
    }
  }

  private static async getRecommendation(
    recommendationId: string,
    tenantId: string
  ): Promise<PricingRecommendation | null> {
    const result = await db('cf_pricing_recommendation')
      .where({ id: recommendationId, tenant_id: tenantId })
      .first();

    if (!result) return null;

    return this.mapToRecommendation(result);
  }

  private static mapToRecommendation(result: any): PricingRecommendation {
    return {
      recommendationId: result.id,
      tenantId: result.tenant_id,
      productId: result.product_id,
      platform: result.platform,
      currentPrice: parseFloat(result.current_price),
      recommendedPrice: parseFloat(result.recommended_price),
      priceChange: parseFloat(result.price_change),
      priceChangePercent: parseFloat(result.price_change_percent),
      strategy: result.strategy,
      confidence: result.confidence,
      reasoning: JSON.parse(result.reasoning || '[]'),
      impact: JSON.parse(result.impact || '{}'),
      validUntil: result.valid_until,
      createdAt: result.created_at
    };
  }
}

export default SmartPricingService;
