/**
 * GrowerAdvisoryAgent
 * Provides personalized recommendations to growers
 *
 * Responsibilities:
 * - Generate planting recommendations based on demand
 * - Provide crop rotation advice
 * - Alert on optimal planting windows
 * - Analyze market opportunities
 * - Track grower performance metrics
 */

import { BaseAgent } from './BaseAgent';
import { AgentConfig, AgentTask, PlantingRecommendation } from './types';
import { getDemandForecaster } from '../demand/forecaster';
import { getBlockchain } from '../blockchain/manager';

interface GrowerProfile {
  growerId: string;
  growerName: string;
  location: { latitude: number; longitude: number };
  availableSpaceSqm: number;
  specializations: string[];
  certifications: string[];
  experienceLevel: 'beginner' | 'intermediate' | 'expert';
  preferredCrops: string[];
  growingHistory: {
    cropType: string;
    successRate: number;
    avgYield: number;
  }[];
}

interface CropRecommendation {
  id: string;
  growerId: string;
  cropType: string;
  recommendedQuantity: number;
  quantityUnit: 'sqm' | 'plants' | 'trays';
  projectedYieldKg: number;
  projectedRevenueUsd: number;
  demandScore: number;
  competitionLevel: 'low' | 'medium' | 'high';
  riskLevel: 'low' | 'medium' | 'high';
  plantingWindow: { start: string; end: string; optimal: string };
  harvestWindow: { start: string; end: string };
  reasoning: string[];
  tips: string[];
  priority: 'low' | 'medium' | 'high' | 'critical';
}

interface RotationAdvice {
  growerId: string;
  currentCrops: string[];
  recommendedNext: string[];
  avoidCrops: string[];
  soilRestPeriod: number; // days
  reasoning: string;
}

interface GrowingOpportunity {
  id: string;
  cropType: string;
  demandGapKg: number;
  currentSupplyKg: number;
  pricePerKg: number;
  windowCloses: string;
  estimatedRevenue: number;
  competitorCount: number;
  successProbability: number;
}

interface GrowerPerformance {
  growerId: string;
  totalPlantsGrown: number;
  successRate: number;
  avgYieldPerSqm: number;
  topCrops: { crop: string; count: number; successRate: number }[];
  carbonFootprintKg: number;
  localDeliveryPercent: number;
  customerSatisfaction: number;
  trend: 'improving' | 'stable' | 'declining';
}

interface SeasonalAlert {
  id: string;
  alertType: 'planting_window' | 'harvest_time' | 'frost_warning' | 'demand_spike' | 'price_change';
  cropType: string;
  message: string;
  actionRequired: string;
  deadline?: string;
  priority: 'low' | 'medium' | 'high' | 'urgent';
}

export class GrowerAdvisoryAgent extends BaseAgent {
  private growerProfiles: Map<string, GrowerProfile> = new Map();
  private recommendations: Map<string, CropRecommendation[]> = new Map();
  private rotationAdvice: Map<string, RotationAdvice> = new Map();
  private opportunities: GrowingOpportunity[] = [];
  private performance: Map<string, GrowerPerformance> = new Map();
  private seasonalAlerts: SeasonalAlert[] = [];

  // Crop knowledge base
  private cropData: Record<string, {
    growingDays: number;
    yieldPerSqm: number;
    seasons: string[];
    companions: string[];
    avoid: string[];
    difficulty: 'easy' | 'moderate' | 'challenging';
  }> = {
      'lettuce': { growingDays: 45, yieldPerSqm: 4, seasons: ['spring', 'fall'], companions: ['carrot', 'radish'], avoid: ['celery'], difficulty: 'easy' },
      'tomato': { growingDays: 80, yieldPerSqm: 8, seasons: ['summer'], companions: ['basil', 'carrot'], avoid: ['brassicas'], difficulty: 'moderate' },
      'spinach': { growingDays: 40, yieldPerSqm: 3, seasons: ['spring', 'fall', 'winter'], companions: ['strawberry', 'pea'], avoid: [], difficulty: 'easy' },
      'kale': { growingDays: 55, yieldPerSqm: 3.5, seasons: ['spring', 'fall', 'winter'], companions: ['onion', 'beet'], avoid: ['strawberry'], difficulty: 'easy' },
      'basil': { growingDays: 30, yieldPerSqm: 2, seasons: ['spring', 'summer'], companions: ['tomato', 'pepper'], avoid: ['sage'], difficulty: 'easy' },
      'pepper': { growingDays: 75, yieldPerSqm: 6, seasons: ['summer'], companions: ['basil', 'carrot'], avoid: ['fennel'], difficulty: 'moderate' },
      'cucumber': { growingDays: 60, yieldPerSqm: 10, seasons: ['summer'], companions: ['bean', 'pea'], avoid: ['potato'], difficulty: 'moderate' },
      'carrot': { growingDays: 70, yieldPerSqm: 5, seasons: ['spring', 'fall'], companions: ['onion', 'lettuce'], avoid: ['dill'], difficulty: 'easy' },
      'microgreens': { growingDays: 14, yieldPerSqm: 1.5, seasons: ['spring', 'summer', 'fall', 'winter'], companions: [], avoid: [], difficulty: 'easy' },
      'strawberry': { growingDays: 90, yieldPerSqm: 3, seasons: ['spring', 'summer'], companions: ['spinach', 'lettuce'], avoid: ['brassicas'], difficulty: 'moderate' }
    };

  constructor() {
    const config: AgentConfig = {
      id: 'grower-advisory-agent',
      name: 'Grower Advisory Agent',
      description: 'Provides personalized growing recommendations',
      enabled: true,
      intervalMs: 300000, // Run every 5 minutes
      priority: 'high',
      maxRetries: 3,
      timeoutMs: 60000
    };
    super(config);
  }

  /**
   * Main execution cycle
   */
  async runOnce(): Promise<AgentTask | null> {
    // Load/update grower profiles from blockchain
    this.updateGrowerProfiles();

    // Generate recommendations for each grower
    for (const [growerId] of this.growerProfiles) {
      const recs = this.generateRecommendations(growerId);
      this.recommendations.set(growerId, recs);

      // Generate rotation advice
      const rotation = this.generateRotationAdvice(growerId);
      this.rotationAdvice.set(growerId, rotation);

      // Update performance metrics
      const perf = this.calculatePerformance(growerId);
      this.performance.set(growerId, perf);
    }

    // Identify market opportunities
    this.opportunities = this.findOpportunities();

    // Generate seasonal alerts
    this.seasonalAlerts = this.generateSeasonalAlerts();

    // Alert growers about urgent opportunities
    this.notifyUrgentOpportunities();

    return this.createTaskResult('grower_advisory', 'completed', {
      growersAdvised: this.growerProfiles.size,
      recommendationsGenerated: Array.from(this.recommendations.values()).flat().length,
      opportunitiesIdentified: this.opportunities.length,
      alertsGenerated: this.seasonalAlerts.length
    });
  }

  /**
   * Update grower profiles from blockchain data
   */
  private updateGrowerProfiles(): void {
    const blockchain = getBlockchain();
    const chain = blockchain.getChain().slice(1);

    const ownerPlants = new Map<string, typeof chain>();

    for (const block of chain) {
      const ownerId = block.plant.owner?.id;
      if (!ownerId) continue;

      const plants = ownerPlants.get(ownerId) || [];
      plants.push(block);
      ownerPlants.set(ownerId, plants);
    }

    for (const [ownerId, plants] of ownerPlants) {
      // Only consider active growers (>2 plants)
      if (plants.length < 3) continue;

      const latestPlant = plants[plants.length - 1];
      const cropTypes = [...new Set(plants.map(p => p.plant.commonName).filter(Boolean))];

      // Calculate success rate
      const healthyPlants = plants.filter(p =>
        ['growing', 'mature', 'flowering', 'fruiting'].includes(p.plant.status)
      ).length;
      const successRate = (healthyPlants / plants.length) * 100;

      // Determine experience level
      let experienceLevel: GrowerProfile['experienceLevel'];
      if (plants.length > 50 && successRate > 80) experienceLevel = 'expert';
      else if (plants.length > 10 && successRate > 60) experienceLevel = 'intermediate';
      else experienceLevel = 'beginner';

      // Build growing history
      const historyMap = new Map<string, { total: number; healthy: number; yield: number }>();
      for (const plant of plants) {
        const crop = plant.plant.commonName || 'unknown';
        const existing = historyMap.get(crop) || { total: 0, healthy: 0, yield: 0 };
        existing.total++;
        if (['growing', 'mature', 'flowering', 'fruiting'].includes(plant.plant.status)) {
          existing.healthy++;
        }
        existing.yield += plant.plant.growthMetrics?.estimatedYieldKg || 2;
        historyMap.set(crop, existing);
      }

      const growingHistory = Array.from(historyMap.entries()).map(([cropType, data]) => ({
        cropType,
        successRate: Math.round((data.healthy / data.total) * 100),
        avgYield: Math.round((data.yield / data.total) * 10) / 10
      }));

      const profile: GrowerProfile = {
        growerId: ownerId,
        growerName: latestPlant.plant.owner?.name || 'Unknown',
        location: latestPlant.plant.location,
        availableSpaceSqm: Math.max(10, plants.length * 2), // Estimate
        specializations: cropTypes.slice(0, 3) as string[],
        certifications: [],
        experienceLevel,
        preferredCrops: cropTypes.slice(0, 5) as string[],
        growingHistory
      };

      this.growerProfiles.set(ownerId, profile);
    }
  }

  /**
   * Generate personalized recommendations
   */
  private generateRecommendations(growerId: string): CropRecommendation[] {
    const profile = this.growerProfiles.get(growerId);
    if (!profile) return [];

    const recommendations: CropRecommendation[] = [];
    const currentSeason = this.getCurrentSeason();
    const forecaster = getDemandForecaster();

    // Get demand signal for grower's region
    const signal = forecaster.generateDemandSignal(
      profile.location.latitude,
      profile.location.longitude,
      50, // 50km radius
      'Local Region',
      currentSeason
    );

    // Find crops with demand gaps
    const demandGaps = signal.demandItems.filter(item => item.gapKg > 10);

    for (const demandItem of demandGaps.slice(0, 5)) {
      const cropData = this.cropData[demandItem.produceType.toLowerCase()];
      if (!cropData) continue;

      // Check if in season
      if (!cropData.seasons.includes(currentSeason)) continue;

      // Check grower's history with this crop
      const history = profile.growingHistory.find(h =>
        h.cropType.toLowerCase() === demandItem.produceType.toLowerCase()
      );

      // Calculate recommended quantity
      const spaceForCrop = Math.min(
        profile.availableSpaceSqm * 0.3, // Max 30% of space per crop
        demandItem.gapKg / cropData.yieldPerSqm
      );

      // Calculate risk level
      let riskLevel: 'low' | 'medium' | 'high';
      if (history && history.successRate > 80) riskLevel = 'low';
      else if (history && history.successRate > 50) riskLevel = 'medium';
      else if (!history && cropData.difficulty === 'challenging') riskLevel = 'high';
      else riskLevel = 'medium';

      // Calculate planting window
      const now = new Date();
      const plantStart = new Date(now);
      const plantOptimal = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
      const plantEnd = new Date(now.getTime() + 21 * 24 * 60 * 60 * 1000);

      const harvestStart = new Date(plantOptimal.getTime() + cropData.growingDays * 24 * 60 * 60 * 1000);
      const harvestEnd = new Date(harvestStart.getTime() + 14 * 24 * 60 * 60 * 1000);

      const projectedYield = spaceForCrop * cropData.yieldPerSqm;
      const projectedRevenue = projectedYield * demandItem.averageWillingPrice;

      recommendations.push({
        id: `rec-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`,
        growerId,
        cropType: demandItem.produceType,
        recommendedQuantity: Math.round(spaceForCrop * 10) / 10,
        quantityUnit: 'sqm',
        projectedYieldKg: Math.round(projectedYield * 10) / 10,
        projectedRevenueUsd: Math.round(projectedRevenue * 100) / 100,
        demandScore: demandItem.aggregatePriority * 10,
        competitionLevel: demandItem.matchedGrowers < 3 ? 'low' :
          demandItem.matchedGrowers < 6 ? 'medium' : 'high',
        riskLevel,
        plantingWindow: {
          start: plantStart.toISOString(),
          end: plantEnd.toISOString(),
          optimal: plantOptimal.toISOString()
        },
        harvestWindow: {
          start: harvestStart.toISOString(),
          end: harvestEnd.toISOString()
        },
        reasoning: [
          `${Math.round(demandItem.gapKg)}kg weekly demand gap in your area`,
          history ? `Your success rate: ${history.successRate}%` : 'New crop opportunity',
          `${demandItem.matchedGrowers} other growers currently supplying`
        ],
        tips: this.generateGrowingTips(demandItem.produceType, profile.experienceLevel),
        priority: demandItem.urgency === 'immediate' ? 'critical' :
          demandItem.urgency === 'this_week' ? 'high' :
            demandItem.urgency === 'this_month' ? 'medium' : 'low'
      });
    }

    return recommendations.sort((a, b) =>
      a.priority === 'critical' ? -1 : b.priority === 'critical' ? 1 :
        a.priority === 'high' ? -1 : b.priority === 'high' ? 1 : 0
    );
  }

  /**
   * Generate crop-specific growing tips
   */
  private generateGrowingTips(cropType: string, experienceLevel: string): string[] {
    const tips: string[] = [];
    const crop = this.cropData[cropType.toLowerCase()];

    if (!crop) return ['Research growing requirements before planting'];

    if (experienceLevel === 'beginner') {
      tips.push(`${cropType} takes approximately ${crop.growingDays} days to harvest`);
      if (crop.difficulty === 'easy') {
        tips.push('Great choice for beginners!');
      }
    }

    if (crop.companions.length > 0) {
      tips.push(`Good companions: ${crop.companions.join(', ')}`);
    }

    if (crop.avoid.length > 0) {
      tips.push(`Avoid planting near: ${crop.avoid.join(', ')}`);
    }

    tips.push(`Expected yield: ${crop.yieldPerSqm}kg per sqm`);

    return tips.slice(0, 4);
  }

  /**
   * Generate rotation advice
   */
  private generateRotationAdvice(growerId: string): RotationAdvice {
    const profile = this.growerProfiles.get(growerId);
    if (!profile) {
      return {
        growerId,
        currentCrops: [],
        recommendedNext: [],
        avoidCrops: [],
        soilRestPeriod: 0,
        reasoning: 'No growing history available'
      };
    }

    const currentCrops = profile.specializations;
    const avoid = new Set<string>();
    const recommended = new Set<string>();

    for (const current of currentCrops) {
      const cropData = this.cropData[current.toLowerCase()];
      if (cropData) {
        cropData.avoid.forEach(c => avoid.add(c));
        cropData.companions.forEach(c => recommended.add(c));
      }
    }

    // Don't recommend crops already being grown
    currentCrops.forEach(c => recommended.delete(c.toLowerCase()));

    return {
      growerId,
      currentCrops,
      recommendedNext: Array.from(recommended).slice(0, 5),
      avoidCrops: Array.from(avoid),
      soilRestPeriod: currentCrops.includes('tomato') || currentCrops.includes('pepper') ? 30 : 14,
      reasoning: `Based on ${currentCrops.length} current crops and companion planting principles`
    };
  }

  /**
   * Calculate grower performance metrics
   */
  private calculatePerformance(growerId: string): GrowerPerformance {
    const profile = this.growerProfiles.get(growerId);

    if (!profile) {
      return {
        growerId,
        totalPlantsGrown: 0,
        successRate: 0,
        avgYieldPerSqm: 0,
        topCrops: [],
        carbonFootprintKg: 0,
        localDeliveryPercent: 100,
        customerSatisfaction: 0,
        trend: 'stable'
      };
    }

    const totalPlants = profile.growingHistory.reduce((sum, h) => sum + h.avgYield * 2, 0);
    const avgSuccess = profile.growingHistory.length > 0
      ? profile.growingHistory.reduce((sum, h) => sum + h.successRate, 0) / profile.growingHistory.length
      : 0;

    const topCrops = profile.growingHistory
      .sort((a, b) => b.avgYield - a.avgYield)
      .slice(0, 3)
      .map(h => ({ crop: h.cropType, count: Math.round(h.avgYield * 2), successRate: h.successRate }));

    return {
      growerId,
      totalPlantsGrown: Math.round(totalPlants),
      successRate: Math.round(avgSuccess),
      avgYieldPerSqm: profile.growingHistory.length > 0
        ? Math.round(profile.growingHistory.reduce((sum, h) => sum + h.avgYield, 0) / profile.growingHistory.length * 10) / 10
        : 0,
      topCrops,
      carbonFootprintKg: Math.round(totalPlants * 0.1 * 10) / 10, // Estimate
      localDeliveryPercent: 85, // Estimate
      customerSatisfaction: Math.min(100, 60 + avgSuccess * 0.4),
      trend: avgSuccess > 75 ? 'improving' : avgSuccess < 50 ? 'declining' : 'stable'
    };
  }

  /**
   * Find market opportunities
   */
  private findOpportunities(): GrowingOpportunity[] {
    const opportunities: GrowingOpportunity[] = [];
    const forecaster = getDemandForecaster();
    const currentSeason = this.getCurrentSeason();

    // Check multiple regions
    const regions = [
      { lat: 40.7128, lon: -74.0060, name: 'Metro' },
      { lat: 40.85, lon: -73.95, name: 'North' },
      { lat: 40.55, lon: -74.15, name: 'South' }
    ];

    for (const region of regions) {
      const signal = forecaster.generateDemandSignal(
        region.lat, region.lon, 50, region.name, currentSeason
      );

      for (const item of signal.demandItems) {
        if (item.gapKg > 20) {
          opportunities.push({
            id: `opp-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`,
            cropType: item.produceType,
            demandGapKg: item.gapKg,
            currentSupplyKg: item.matchedSupply,
            pricePerKg: item.averageWillingPrice,
            windowCloses: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString(),
            estimatedRevenue: item.gapKg * item.averageWillingPrice,
            competitorCount: item.matchedGrowers,
            successProbability: item.inSeason ? 0.8 : 0.5
          });
        }
      }
    }

    return opportunities.sort((a, b) => b.estimatedRevenue - a.estimatedRevenue).slice(0, 20);
  }

  /**
   * Generate seasonal alerts
   */
  private generateSeasonalAlerts(): SeasonalAlert[] {
    const alerts: SeasonalAlert[] = [];
    const currentSeason = this.getCurrentSeason();
    const nextSeason = this.getNextSeason(currentSeason);

    // Planting window alerts
    for (const [crop, data] of Object.entries(this.cropData)) {
      if (data.seasons.includes(nextSeason) && !data.seasons.includes(currentSeason)) {
        alerts.push({
          id: `alert-${Date.now()}-${crop}`,
          alertType: 'planting_window',
          cropType: crop,
          message: `${crop} planting season approaching - prepare to plant in ${nextSeason}`,
          actionRequired: 'Order seeds and prepare growing area',
          deadline: this.getSeasonStartDate(nextSeason),
          priority: 'medium'
        });
      }
    }

    // Demand spike alerts
    for (const opp of this.opportunities.slice(0, 3)) {
      if (opp.demandGapKg > 100) {
        alerts.push({
          id: `alert-${Date.now()}-demand-${opp.cropType}`,
          alertType: 'demand_spike',
          cropType: opp.cropType,
          message: `High demand for ${opp.cropType}: ${Math.round(opp.demandGapKg)}kg weekly gap`,
          actionRequired: 'Consider expanding production',
          priority: 'high'
        });
      }
    }

    return alerts;
  }

  /**
   * Notify growers about urgent opportunities
   */
  private notifyUrgentOpportunities(): void {
    const urgentOpps = this.opportunities.filter(o =>
      o.estimatedRevenue > 500 && o.competitorCount < 3
    );

    for (const opp of urgentOpps.slice(0, 3)) {
      this.createAlert('info', `Growing Opportunity: ${opp.cropType}`,
        `${Math.round(opp.demandGapKg)}kg demand gap, estimated $${Math.round(opp.estimatedRevenue)} revenue`,
        {
          actionRequired: `Consider planting ${opp.cropType}`,
          relatedEntityType: 'opportunity'
        }
      );
    }
  }

  /**
   * Get current season
   */
  private getCurrentSeason(): 'spring' | 'summer' | 'fall' | 'winter' {
    const month = new Date().getMonth();
    if (month >= 2 && month <= 4) return 'spring';
    if (month >= 5 && month <= 7) return 'summer';
    if (month >= 8 && month <= 10) return 'fall';
    return 'winter';
  }

  /**
   * Get next season
   */
  private getNextSeason(current: string): 'spring' | 'summer' | 'fall' | 'winter' {
    const order = ['spring', 'summer', 'fall', 'winter'];
    const idx = order.indexOf(current);
    return order[(idx + 1) % 4] as any;
  }

  /**
   * Get season start date
   */
  private getSeasonStartDate(season: string): string {
    const year = new Date().getFullYear();
    const dates: Record<string, string> = {
      'spring': `${year}-03-20`,
      'summer': `${year}-06-21`,
      'fall': `${year}-09-22`,
      'winter': `${year}-12-21`
    };
    return dates[season] || dates['spring'];
  }

  /**
   * Register a grower profile
   */
  registerGrowerProfile(profile: GrowerProfile): void {
    this.growerProfiles.set(profile.growerId, profile);
  }

  /**
   * Get grower profile
   */
  getGrowerProfile(growerId: string): GrowerProfile | null {
    return this.growerProfiles.get(growerId) || null;
  }

  /**
   * Get recommendations for a grower
   */
  getRecommendations(growerId: string): CropRecommendation[] {
    return this.recommendations.get(growerId) || [];
  }

  /**
   * Get rotation advice for a grower
   */
  getRotationAdvice(growerId: string): RotationAdvice | null {
    return this.rotationAdvice.get(growerId) || null;
  }

  /**
   * Get market opportunities
   */
  getOpportunities(): GrowingOpportunity[] {
    return this.opportunities;
  }

  /**
   * Get grower performance
   */
  getPerformance(growerId: string): GrowerPerformance | null {
    return this.performance.get(growerId) || null;
  }

  /**
   * Get seasonal alerts
   */
  getSeasonalAlerts(): SeasonalAlert[] {
    return this.seasonalAlerts;
  }
}

// Singleton instance
let growerAgentInstance: GrowerAdvisoryAgent | null = null;

export function getGrowerAdvisoryAgent(): GrowerAdvisoryAgent {
  if (!growerAgentInstance) {
    growerAgentInstance = new GrowerAdvisoryAgent();
  }
  return growerAgentInstance;
}
