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

export interface Strategy {
  id: string;
  name: string;
  description: string;
  category: 'PRICING' | 'ADVERTISING' | 'PRODUCT_SELECTION' | 'INVENTORY' | 'LOGISTICS' | 'MARKETING';
  risk_level: 'LOW' | 'MEDIUM' | 'HIGH';
  price: number;
  billing_type: 'FREE' | 'ONE_TIME' | 'SUBSCRIPTION' | 'USAGE_BASED';
  parameters: Record<string, any>;
  default_config: Record<string, any>;
  avg_roi: number;
  usage_count: number;
  success_rate: number;
  tags: string[];
  is_active: boolean;
  is_featured: boolean;
  created_by: string;
  created_at: Date;
  updated_at: Date;
}

export interface MerchantStrategy {
  id: string;
  tenant_id: string;
  strategy_id: string;
  status: 'ACTIVE' | 'PAUSED' | 'COMPLETED' | 'FAILED';
  config: Record<string, any>;
  results: Record<string, any>;
  roi_achieved: number;
  revenue_generated: number;
  activated_at: Date;
  completed_at: Date | null;
  created_at: Date;
  updated_at: Date;
}

export interface StrategyActivationInput {
  tenantId: string;
  strategyId: string;
  config?: Record<string, any>;
}

export class StrategyService {
  private static instance: StrategyService;

  private constructor() {}

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

  async createStrategy(strategy: Omit<Strategy, 'id' | 'created_at' | 'updated_at'>): Promise<Strategy> {
    const newStrategy: Strategy = {
      ...strategy,
      id: uuidv4(),
      created_at: new Date(),
      updated_at: new Date()
    };

    await db('cf_strategies').insert({
      ...newStrategy,
      parameters: JSON.stringify(newStrategy.parameters),
      default_config: JSON.stringify(newStrategy.default_config),
      tags: JSON.stringify(newStrategy.tags)
    });

    logger.info(`[StrategyService] Created strategy: ${newStrategy.name}`);
    return newStrategy;
  }

  async getStrategyById(strategyId: string): Promise<Strategy | null> {
    const strategy = await db('cf_strategies')
      .where('id', strategyId)
      .first();

    if (!strategy) return null;

    return this.mapStrategyFromDb(strategy);
  }

  async getStrategiesByCategory(category: string): Promise<Strategy[]> {
    const strategies = await db('cf_strategies')
      .where('category', category)
      .where('is_active', true)
      .orderBy('avg_roi', 'desc');

    return strategies.map(this.mapStrategyFromDb);
  }

  async getAllStrategies(options?: {
    category?: string;
    isActive?: boolean;
    isFeatured?: boolean;
    limit?: number;
    offset?: number;
  }): Promise<{ strategies: Strategy[]; total: number }> {
    let query = db('cf_strategies');

    if (options?.category) {
      query = query.where('category', options.category);
    }
    if (options?.isActive !== undefined) {
      query = query.where('is_active', options.isActive);
    }
    if (options?.isFeatured !== undefined) {
      query = query.where('is_featured', options.isFeatured);
    }

    const total = await query.clone().count('* as count').first();

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

    const strategies = await query.orderBy('avg_roi', 'desc');

    return {
      strategies: strategies.map(this.mapStrategyFromDb),
      total: Number(total?.count) || 0
    };
  }

  async getFeaturedStrategies(limit: number = 5): Promise<Strategy[]> {
    const strategies = await db('cf_strategies')
      .where('is_active', true)
      .where('is_featured', true)
      .orderBy('usage_count', 'desc')
      .limit(limit);

    return strategies.map(this.mapStrategyFromDb);
  }

  async activateStrategy(input: StrategyActivationInput): Promise<MerchantStrategy> {
    const { tenantId, strategyId, config } = input;

    const strategy = await this.getStrategyById(strategyId);
    if (!strategy) {
      throw new Error('Strategy not found');
    }

    const existingActivation = await db('cf_merchant_strategies')
      .where('tenant_id', tenantId)
      .where('strategy_id', strategyId)
      .where('status', 'ACTIVE')
      .first();

    if (existingActivation) {
      throw new Error('Strategy already activated for this tenant');
    }

    const merchantStrategy: MerchantStrategy = {
      id: uuidv4(),
      tenant_id: tenantId,
      strategy_id: strategyId,
      status: 'ACTIVE',
      config: config || strategy.default_config,
      results: {},
      roi_achieved: 0,
      revenue_generated: 0,
      activated_at: new Date(),
      completed_at: null,
      created_at: new Date(),
      updated_at: new Date()
    };

    await db('cf_merchant_strategies').insert({
      ...merchantStrategy,
      config: JSON.stringify(merchantStrategy.config),
      results: JSON.stringify(merchantStrategy.results)
    });

    await db('cf_strategies')
      .where('id', strategyId)
      .increment('usage_count', 1);

    logger.info(`[StrategyService] Strategy ${strategy.name} activated for tenant ${tenantId}`);
    return merchantStrategy;
  }

  async pauseStrategy(merchantStrategyId: string, tenantId: string): Promise<void> {
    const result = await db('cf_merchant_strategies')
      .where('id', merchantStrategyId)
      .where('tenant_id', tenantId)
      .update({
        status: 'PAUSED',
        updated_at: new Date()
      });

    if (result === 0) {
      throw new Error('Merchant strategy not found or not owned by tenant');
    }

    logger.info(`[StrategyService] Strategy ${merchantStrategyId} paused`);
  }

  async resumeStrategy(merchantStrategyId: string, tenantId: string): Promise<void> {
    const result = await db('cf_merchant_strategies')
      .where('id', merchantStrategyId)
      .where('tenant_id', tenantId)
      .where('status', 'PAUSED')
      .update({
        status: 'ACTIVE',
        updated_at: new Date()
      });

    if (result === 0) {
      throw new Error('Paused merchant strategy not found or not owned by tenant');
    }

    logger.info(`[StrategyService] Strategy ${merchantStrategyId} resumed`);
  }

  async completeStrategy(
    merchantStrategyId: string,
    tenantId: string,
    results: { roi: number; revenue: number }
  ): Promise<void> {
    const merchantStrategy = await db('cf_merchant_strategies')
      .where('id', merchantStrategyId)
      .where('tenant_id', tenantId)
      .first();

    if (!merchantStrategy) {
      throw new Error('Merchant strategy not found');
    }

    await db('cf_merchant_strategies')
      .where('id', merchantStrategyId)
      .update({
        status: 'COMPLETED',
        results: JSON.stringify(results),
        roi_achieved: results.roi,
        revenue_generated: results.revenue,
        completed_at: new Date(),
        updated_at: new Date()
      });

    await this.updateStrategyStats(merchantStrategy.strategy_id);

    logger.info(`[StrategyService] Strategy ${merchantStrategyId} completed with ROI: ${results.roi}`);
  }

  async getMerchantStrategies(
    tenantId: string,
    status?: 'ACTIVE' | 'PAUSED' | 'COMPLETED' | 'FAILED'
  ): Promise<(MerchantStrategy & { strategy: Strategy })[]> {
    let query = db('cf_merchant_strategies as ms')
      .join('cf_strategies as s', 'ms.strategy_id', 's.id')
      .where('ms.tenant_id', tenantId)
      .select('ms.*', 's.*');

    if (status) {
      query = query.where('ms.status', status);
    }

    const results = await query.orderBy('ms.created_at', 'desc');

    return results.map(row => ({
      id: row.id,
      tenant_id: row.tenant_id,
      strategy_id: row.strategy_id,
      status: row.status,
      config: typeof row.config === 'string' ? JSON.parse(row.config) : row.config,
      results: typeof row.results === 'string' ? JSON.parse(row.results) : row.results,
      roi_achieved: parseFloat(row.roi_achieved) || 0,
      revenue_generated: parseFloat(row.revenue_generated) || 0,
      activated_at: row.activated_at,
      completed_at: row.completed_at,
      created_at: row.created_at,
      updated_at: row.updated_at,
      strategy: this.mapStrategyFromDb({
        id: row.strategy_id,
        name: row.name,
        description: row.description,
        category: row.category,
        risk_level: row.risk_level,
        price: row.price,
        billing_type: row.billing_type,
        parameters: row.parameters,
        default_config: row.default_config,
        avg_roi: row.avg_roi,
        usage_count: row.usage_count,
        success_rate: row.success_rate,
        tags: row.tags,
        is_active: row.is_active,
        is_featured: row.is_featured,
        created_by: row.created_by,
        created_at: row.s_created_at || row.created_at,
        updated_at: row.s_updated_at || row.updated_at
      })
    }));
  }

  async updateStrategyStats(strategyId: string): Promise<void> {
    const stats = await db('cf_merchant_strategies')
      .where('strategy_id', strategyId)
      .where('status', 'COMPLETED')
      .select('roi_achieved');

    const completedCount = stats.length;
    const successCount = stats.filter(s => s.roi_achieved > 0).length;
    const avgRoi = completedCount > 0
      ? stats.reduce((sum, s) => sum + parseFloat(s.roi_achieved as any) || 0, 0) / completedCount
      : 0;
    const successRate = completedCount > 0 ? Math.round((successCount / completedCount) * 100) : 0;

    await db('cf_strategies')
      .where('id', strategyId)
      .update({
        avg_roi: avgRoi,
        success_rate: successRate,
        updated_at: new Date()
      });

    logger.info(`[StrategyService] Updated stats for strategy ${strategyId}: avg_roi=${avgRoi}, success_rate=${successRate}%`);
  }

  async searchStrategies(query: string): Promise<Strategy[]> {
    const strategies = await db('cf_strategies')
      .where('is_active', true)
      .where(function() {
        this.where('name', 'like', `%${query}%`)
          .orWhere('description', 'like', `%${query}%`);
      })
      .orderBy('avg_roi', 'desc')
      .limit(20);

    return strategies.map(this.mapStrategyFromDb);
  }

  async getStrategiesByTags(tags: string[]): Promise<Strategy[]> {
    const strategies = await db('cf_strategies')
      .where('is_active', true);

    return strategies
      .map(this.mapStrategyFromDb)
      .filter(s => s.tags.some(t => tags.includes(t)));
  }

  private mapStrategyFromDb(row: any): Strategy {
    return {
      id: row.id,
      name: row.name,
      description: row.description,
      category: row.category,
      risk_level: row.risk_level,
      price: parseFloat(row.price) || 0,
      billing_type: row.billing_type,
      parameters: typeof row.parameters === 'string' ? JSON.parse(row.parameters) : row.parameters,
      default_config: typeof row.default_config === 'string' ? JSON.parse(row.default_config) : row.default_config,
      avg_roi: parseFloat(row.avg_roi) || 0,
      usage_count: row.usage_count || 0,
      success_rate: row.success_rate || 0,
      tags: typeof row.tags === 'string' ? JSON.parse(row.tags) : row.tags,
      is_active: row.is_active,
      is_featured: row.is_featured,
      created_by: row.created_by,
      created_at: row.created_at,
      updated_at: row.updated_at
    };
  }
}

export default StrategyService.getInstance();
