/**
 * EnvironmentAnalysisAgent
 * Analyzes growing conditions and provides optimization recommendations
 *
 * Responsibilities:
 * - Compare growing environments across plants
 * - Identify optimal conditions for each species
 * - Generate environment improvement recommendations
 * - Track environmental impacts on plant health
 * - Learn from successful growing patterns
 */

import { BaseAgent } from './BaseAgent';
import { AgentConfig, AgentTask } from './types';
import { getBlockchain } from '../blockchain/manager';
import { PlantBlock, GrowingEnvironment, GrowthMetrics } from '../blockchain/types';

interface EnvironmentProfile {
  species: string;
  sampleSize: number;
  optimalConditions: {
    soilPH: { min: number; max: number; optimal: number };
    temperature: { min: number; max: number; optimal: number };
    humidity: { min: number; max: number; optimal: number };
    lightHours: { min: number; max: number; optimal: number };
    wateringFrequency: string;
    preferredSoilType: string[];
  };
  successRate: number;
  commonIssues: string[];
}

interface EnvironmentComparison {
  plant1Id: string;
  plant2Id: string;
  similarityScore: number;
  matchingFactors: string[];
  differingFactors: { factor: string; plant1Value: any; plant2Value: any }[];
  recommendation: string;
}

interface PlantEnvironmentScore {
  plantId: string;
  species: string;
  overallScore: number;
  categoryScores: {
    soil: number;
    lighting: number;
    watering: number;
    climate: number;
    nutrients: number;
  };
  improvements: EnvironmentImprovement[];
}

interface EnvironmentImprovement {
  category: string;
  currentState: string;
  recommendedState: string;
  priority: 'low' | 'medium' | 'high';
  expectedImpact: string;
  difficulty: 'easy' | 'moderate' | 'difficult';
}

interface SuccessPattern {
  patternId: string;
  species: string;
  conditions: Partial<GrowingEnvironment>;
  successMetric: 'growth_rate' | 'health' | 'yield' | 'survival';
  successValue: number;
  sampleSize: number;
  confidence: number;
}

export class EnvironmentAnalysisAgent extends BaseAgent {
  private speciesProfiles: Map<string, EnvironmentProfile> = new Map();
  private plantScores: Map<string, PlantEnvironmentScore> = new Map();
  private successPatterns: SuccessPattern[] = [];
  private comparisonCache: Map<string, EnvironmentComparison> = new Map();

  constructor() {
    const config: AgentConfig = {
      id: 'environment-analysis-agent',
      name: 'Environment Analysis Agent',
      description: 'Analyzes and optimizes growing conditions',
      enabled: true,
      intervalMs: 180000, // Run every 3 minutes
      priority: 'medium',
      maxRetries: 3,
      timeoutMs: 45000
    };
    super(config);

    // Initialize with known species profiles
    this.initializeKnownProfiles();
  }

  /**
   * Initialize profiles for common species
   */
  private initializeKnownProfiles(): void {
    const commonProfiles: EnvironmentProfile[] = [
      {
        species: 'Tomato',
        sampleSize: 0,
        optimalConditions: {
          soilPH: { min: 6.0, max: 6.8, optimal: 6.5 },
          temperature: { min: 18, max: 29, optimal: 24 },
          humidity: { min: 50, max: 70, optimal: 60 },
          lightHours: { min: 8, max: 12, optimal: 10 },
          wateringFrequency: 'daily',
          preferredSoilType: ['loamy', 'sandy_loam']
        },
        successRate: 85,
        commonIssues: ['blossom_end_rot', 'early_blight', 'aphids']
      },
      {
        species: 'Lettuce',
        sampleSize: 0,
        optimalConditions: {
          soilPH: { min: 6.0, max: 7.0, optimal: 6.5 },
          temperature: { min: 10, max: 21, optimal: 16 },
          humidity: { min: 50, max: 70, optimal: 60 },
          lightHours: { min: 10, max: 14, optimal: 12 },
          wateringFrequency: 'daily',
          preferredSoilType: ['loamy', 'clay_loam']
        },
        successRate: 90,
        commonIssues: ['bolting', 'tip_burn', 'slugs']
      },
      {
        species: 'Basil',
        sampleSize: 0,
        optimalConditions: {
          soilPH: { min: 6.0, max: 7.0, optimal: 6.5 },
          temperature: { min: 18, max: 29, optimal: 24 },
          humidity: { min: 40, max: 60, optimal: 50 },
          lightHours: { min: 6, max: 8, optimal: 7 },
          wateringFrequency: 'every_2_days',
          preferredSoilType: ['loamy', 'sandy_loam']
        },
        successRate: 88,
        commonIssues: ['downy_mildew', 'fusarium_wilt', 'aphids']
      },
      {
        species: 'Pepper',
        sampleSize: 0,
        optimalConditions: {
          soilPH: { min: 6.0, max: 6.8, optimal: 6.4 },
          temperature: { min: 18, max: 32, optimal: 26 },
          humidity: { min: 50, max: 70, optimal: 60 },
          lightHours: { min: 8, max: 12, optimal: 10 },
          wateringFrequency: 'every_2_days',
          preferredSoilType: ['loamy', 'sandy_loam']
        },
        successRate: 82,
        commonIssues: ['blossom_drop', 'bacterial_spot', 'aphids']
      }
    ];

    for (const profile of commonProfiles) {
      this.speciesProfiles.set(profile.species.toLowerCase(), profile);
    }
  }

  /**
   * Main execution cycle
   */
  async runOnce(): Promise<AgentTask | null> {
    const blockchain = getBlockchain();
    const chain = blockchain.getChain();
    const plants = chain.slice(1); // Skip genesis

    let profilesUpdated = 0;
    let scoresCalculated = 0;
    let patternsIdentified = 0;

    // Group plants by species for analysis
    const speciesGroups = this.groupBySpecies(plants);

    // Update species profiles based on actual data
    for (const [species, speciesPlants] of speciesGroups) {
      this.updateSpeciesProfile(species, speciesPlants);
      profilesUpdated++;
    }

    // Calculate environment scores for each plant
    for (const block of plants) {
      const score = this.calculateEnvironmentScore(block);
      this.plantScores.set(block.plant.id, score);
      scoresCalculated++;

      // Alert for plants with poor environment scores
      if (score.overallScore < 50) {
        this.createAlert('warning', `Poor Growing Conditions: ${block.plant.commonName}`,
          `Plant ${block.plant.id} has environment score of ${score.overallScore}`,
          {
            actionRequired: score.improvements[0]?.recommendedState || 'Review growing conditions',
            relatedEntityId: block.plant.id,
            relatedEntityType: 'plant'
          }
        );
      }
    }

    // Identify success patterns
    const newPatterns = this.identifySuccessPatterns(plants);
    this.successPatterns = [...this.successPatterns, ...newPatterns].slice(-100);
    patternsIdentified = newPatterns.length;

    // Clean comparison cache
    if (this.comparisonCache.size > 1000) {
      this.comparisonCache.clear();
    }

    return this.createTaskResult('environment_analysis', 'completed', {
      plantsAnalyzed: plants.length,
      profilesUpdated,
      scoresCalculated,
      patternsIdentified,
      avgEnvironmentScore: this.calculateAverageScore()
    });
  }

  /**
   * Group plants by species
   */
  private groupBySpecies(plants: PlantBlock[]): Map<string, PlantBlock[]> {
    const groups = new Map<string, PlantBlock[]>();

    for (const block of plants) {
      const species = block.plant.commonName?.toLowerCase() || 'unknown';
      const group = groups.get(species) || [];
      group.push(block);
      groups.set(species, group);
    }

    return groups;
  }

  /**
   * Update species profile based on actual data
   */
  private updateSpeciesProfile(species: string, plants: PlantBlock[]): void {
    const existing = this.speciesProfiles.get(species);
    const plantsWithEnv = plants.filter(p => p.plant.environment);

    if (plantsWithEnv.length < 3) {
      // Not enough data to update profile
      if (existing) {
        existing.sampleSize = plantsWithEnv.length;
      }
      return;
    }

    // Calculate statistics from actual data
    const pHValues: number[] = [];
    const tempValues: number[] = [];
    const humidityValues: number[] = [];
    const lightValues: number[] = [];
    const healthyPlants = plantsWithEnv.filter(p =>
      p.plant.status === 'growing' || p.plant.status === 'mature' || p.plant.status === 'flowering'
    );

    for (const block of healthyPlants) {
      const env = block.plant.environment;
      if (env?.soil?.pH) pHValues.push(env.soil.pH);
      if (env?.climate?.avgTemperature) tempValues.push(env.climate.avgTemperature);
      if (env?.climate?.avgHumidity) humidityValues.push(env.climate.avgHumidity);
      if (env?.lighting?.hoursPerDay) lightValues.push(env.lighting.hoursPerDay);
    }

    const profile: EnvironmentProfile = existing || {
      species,
      sampleSize: 0,
      optimalConditions: {
        soilPH: { min: 6.0, max: 7.0, optimal: 6.5 },
        temperature: { min: 15, max: 30, optimal: 22 },
        humidity: { min: 40, max: 80, optimal: 60 },
        lightHours: { min: 6, max: 12, optimal: 8 },
        wateringFrequency: 'as_needed',
        preferredSoilType: []
      },
      successRate: 0,
      commonIssues: []
    };

    // Update with statistical analysis
    if (pHValues.length > 0) {
      profile.optimalConditions.soilPH = this.calculateOptimalRange(pHValues);
    }
    if (tempValues.length > 0) {
      profile.optimalConditions.temperature = this.calculateOptimalRange(tempValues);
    }
    if (humidityValues.length > 0) {
      profile.optimalConditions.humidity = this.calculateOptimalRange(humidityValues);
    }
    if (lightValues.length > 0) {
      profile.optimalConditions.lightHours = this.calculateOptimalRange(lightValues);
    }

    profile.sampleSize = plantsWithEnv.length;
    profile.successRate = (healthyPlants.length / plantsWithEnv.length) * 100;

    this.speciesProfiles.set(species, profile);
  }

  /**
   * Calculate optimal range from values
   */
  private calculateOptimalRange(values: number[]): { min: number; max: number; optimal: number } {
    const sorted = [...values].sort((a, b) => a - b);
    const n = sorted.length;

    return {
      min: sorted[Math.floor(n * 0.1)] || sorted[0],
      max: sorted[Math.floor(n * 0.9)] || sorted[n - 1],
      optimal: sorted[Math.floor(n * 0.5)] // Median
    };
  }

  /**
   * Calculate environment score for a plant
   */
  private calculateEnvironmentScore(block: PlantBlock): PlantEnvironmentScore {
    const plant = block.plant;
    const env = plant.environment;
    const species = plant.commonName?.toLowerCase() || 'unknown';
    const profile = this.speciesProfiles.get(species);

    const improvements: EnvironmentImprovement[] = [];
    let soilScore = 50;
    let lightingScore = 50;
    let wateringScore = 50;
    let climateScore = 50;
    let nutrientsScore = 50;

    if (env && profile) {
      // Soil analysis
      if (env.soil) {
        const pHDiff = env.soil.pH
          ? Math.abs(env.soil.pH - profile.optimalConditions.soilPH.optimal)
          : 1;
        soilScore = Math.max(0, 100 - pHDiff * 20);

        if (pHDiff > 0.5) {
          improvements.push({
            category: 'soil',
            currentState: `pH ${env.soil.pH?.toFixed(1) || 'unknown'}`,
            recommendedState: `pH ${profile.optimalConditions.soilPH.optimal}`,
            priority: pHDiff > 1 ? 'high' : 'medium',
            expectedImpact: 'Improved nutrient uptake',
            difficulty: 'moderate'
          });
        }
      }

      // Lighting analysis
      if (env.lighting) {
        const lightDiff = env.lighting.hoursPerDay
          ? Math.abs(env.lighting.hoursPerDay - profile.optimalConditions.lightHours.optimal)
          : 2;
        lightingScore = Math.max(0, 100 - lightDiff * 15);

        if (lightDiff > 2) {
          improvements.push({
            category: 'lighting',
            currentState: `${env.lighting.hoursPerDay || 'unknown'} hours/day`,
            recommendedState: `${profile.optimalConditions.lightHours.optimal} hours/day`,
            priority: lightDiff > 4 ? 'high' : 'medium',
            expectedImpact: 'Better photosynthesis and growth',
            difficulty: env.lighting.type === 'artificial' ? 'easy' : 'difficult'
          });
        }
      }

      // Climate analysis
      if (env.climate) {
        const tempDiff = env.climate.avgTemperature
          ? Math.abs(env.climate.avgTemperature - profile.optimalConditions.temperature.optimal)
          : 5;
        const humDiff = env.climate.avgHumidity
          ? Math.abs(env.climate.avgHumidity - profile.optimalConditions.humidity.optimal)
          : 10;

        climateScore = Math.max(0, 100 - tempDiff * 5 - humDiff * 1);

        if (tempDiff > 3) {
          improvements.push({
            category: 'climate',
            currentState: `${env.climate.avgTemperature?.toFixed(1) || 'unknown'}°C`,
            recommendedState: `${profile.optimalConditions.temperature.optimal}°C`,
            priority: tempDiff > 6 ? 'high' : 'medium',
            expectedImpact: 'Reduced stress and improved growth',
            difficulty: 'moderate'
          });
        }
      }

      // Watering analysis
      if (env.watering) {
        wateringScore = 70; // Base score if watering data exists
        if (env.watering.frequency === profile.optimalConditions.wateringFrequency) {
          wateringScore = 90;
        }
      }

      // Nutrients analysis
      if (env.nutrients) {
        nutrientsScore = 75; // Base score if nutrient data exists
        if (env.nutrients.fertilizer?.schedule === 'regular') {
          nutrientsScore = 90;
        }
      }
    }

    const overallScore = Math.round(
      (soilScore + lightingScore + wateringScore + climateScore + nutrientsScore) / 5
    );

    return {
      plantId: plant.id,
      species: plant.commonName || 'Unknown',
      overallScore,
      categoryScores: {
        soil: Math.round(soilScore),
        lighting: Math.round(lightingScore),
        watering: Math.round(wateringScore),
        climate: Math.round(climateScore),
        nutrients: Math.round(nutrientsScore)
      },
      improvements: improvements.sort((a, b) =>
        a.priority === 'high' ? -1 : b.priority === 'high' ? 1 : 0
      )
    };
  }

  /**
   * Identify success patterns from plant data
   */
  private identifySuccessPatterns(plants: PlantBlock[]): SuccessPattern[] {
    const patterns: SuccessPattern[] = [];

    // Group healthy plants by species
    const healthyBySpecies = new Map<string, PlantBlock[]>();

    for (const block of plants) {
      if (block.plant.status === 'mature' || block.plant.status === 'flowering' || block.plant.status === 'fruiting') {
        const species = block.plant.commonName?.toLowerCase() || 'unknown';
        const group = healthyBySpecies.get(species) || [];
        group.push(block);
        healthyBySpecies.set(species, group);
      }
    }

    // Identify common conditions among successful plants
    for (const [species, successPlants] of healthyBySpecies) {
      if (successPlants.length < 2) continue;

      const plantsWithEnv = successPlants.filter(p => p.plant.environment);
      if (plantsWithEnv.length < 2) continue;

      // Find common soil types
      const soilTypes = plantsWithEnv
        .map(p => p.plant.environment?.soil?.soilType)
        .filter(Boolean);

      const commonSoilType = this.findMostCommon(soilTypes as string[]);

      if (commonSoilType) {
        patterns.push({
          patternId: `pattern-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`,
          species,
          conditions: { soil: { soilType: commonSoilType } } as any,
          successMetric: 'health',
          successValue: 85,
          sampleSize: plantsWithEnv.length,
          confidence: Math.min(95, 50 + plantsWithEnv.length * 10)
        });
      }
    }

    return patterns;
  }

  /**
   * Find most common value in array
   */
  private findMostCommon(arr: string[]): string | null {
    if (arr.length === 0) return null;

    const counts = new Map<string, number>();
    for (const item of arr) {
      counts.set(item, (counts.get(item) || 0) + 1);
    }

    let maxCount = 0;
    let mostCommon: string | null = null;

    for (const [item, count] of counts) {
      if (count > maxCount) {
        maxCount = count;
        mostCommon = item;
      }
    }

    return mostCommon;
  }

  /**
   * Calculate average environment score
   */
  private calculateAverageScore(): number {
    const scores = Array.from(this.plantScores.values());
    if (scores.length === 0) return 0;
    return Math.round(
      scores.reduce((sum, s) => sum + s.overallScore, 0) / scores.length
    );
  }

  /**
   * Compare two plant environments
   */
  compareEnvironments(plant1Id: string, plant2Id: string): EnvironmentComparison | null {
    const cacheKey = [plant1Id, plant2Id].sort().join('-');
    const cached = this.comparisonCache.get(cacheKey);
    if (cached) return cached;

    const blockchain = getBlockchain();
    const chain = blockchain.getChain();

    const block1 = chain.find(b => b.plant.id === plant1Id);
    const block2 = chain.find(b => b.plant.id === plant2Id);

    if (!block1 || !block2) return null;

    const env1 = block1.plant.environment;
    const env2 = block2.plant.environment;

    const matchingFactors: string[] = [];
    const differingFactors: { factor: string; plant1Value: any; plant2Value: any }[] = [];
    let matchScore = 0;
    let totalFactors = 0;

    // Compare soil
    if (env1?.soil && env2?.soil) {
      totalFactors++;
      if (env1.soil.soilType === env2.soil.soilType) {
        matchingFactors.push('Soil type');
        matchScore++;
      } else {
        differingFactors.push({
          factor: 'Soil type',
          plant1Value: env1.soil.soilType,
          plant2Value: env2.soil.soilType
        });
      }

      totalFactors++;
      if (Math.abs((env1.soil.pH || 0) - (env2.soil.pH || 0)) < 0.5) {
        matchingFactors.push('Soil pH');
        matchScore++;
      } else {
        differingFactors.push({
          factor: 'Soil pH',
          plant1Value: env1.soil.pH,
          plant2Value: env2.soil.pH
        });
      }
    }

    // Compare lighting
    if (env1?.lighting && env2?.lighting) {
      totalFactors++;
      if (env1.lighting.type === env2.lighting.type) {
        matchingFactors.push('Light type');
        matchScore++;
      } else {
        differingFactors.push({
          factor: 'Light type',
          plant1Value: env1.lighting.type,
          plant2Value: env2.lighting.type
        });
      }
    }

    // Compare climate
    if (env1?.climate && env2?.climate) {
      totalFactors++;
      const tempDiff = Math.abs(
        (env1.climate.avgTemperature || 0) - (env2.climate.avgTemperature || 0)
      );
      if (tempDiff < 3) {
        matchingFactors.push('Temperature');
        matchScore++;
      } else {
        differingFactors.push({
          factor: 'Temperature',
          plant1Value: env1.climate.avgTemperature,
          plant2Value: env2.climate.avgTemperature
        });
      }
    }

    const similarityScore = totalFactors > 0
      ? Math.round((matchScore / totalFactors) * 100)
      : 50;

    let recommendation = '';
    if (similarityScore > 80) {
      recommendation = 'Very similar environments - good candidates for companion planting';
    } else if (similarityScore > 60) {
      recommendation = 'Moderately similar - consider adjusting differing factors';
    } else {
      recommendation = 'Different environments - may require separate growing areas';
    }

    const comparison: EnvironmentComparison = {
      plant1Id,
      plant2Id,
      similarityScore,
      matchingFactors,
      differingFactors,
      recommendation
    };

    this.comparisonCache.set(cacheKey, comparison);
    return comparison;
  }

  /**
   * Get species profile
   */
  getSpeciesProfile(species: string): EnvironmentProfile | null {
    return this.speciesProfiles.get(species.toLowerCase()) || null;
  }

  /**
   * Get all species profiles
   */
  getAllProfiles(): EnvironmentProfile[] {
    return Array.from(this.speciesProfiles.values());
  }

  /**
   * Get plant environment score
   */
  getPlantScore(plantId: string): PlantEnvironmentScore | null {
    return this.plantScores.get(plantId) || null;
  }

  /**
   * Get success patterns
   */
  getSuccessPatterns(): SuccessPattern[] {
    return this.successPatterns;
  }

  /**
   * Get recommendations for a species
   */
  getSpeciesRecommendations(species: string): {
    profile: EnvironmentProfile | null;
    patterns: SuccessPattern[];
    tips: string[];
  } {
    const profile = this.speciesProfiles.get(species.toLowerCase());
    const patterns = this.successPatterns.filter(p => p.species === species.toLowerCase());

    const tips: string[] = [];
    if (profile) {
      tips.push(`Maintain soil pH between ${profile.optimalConditions.soilPH.min} and ${profile.optimalConditions.soilPH.max}`);
      tips.push(`Keep temperature between ${profile.optimalConditions.temperature.min}°C and ${profile.optimalConditions.temperature.max}°C`);
      tips.push(`Provide ${profile.optimalConditions.lightHours.optimal} hours of light daily`);
      if (profile.commonIssues.length > 0) {
        tips.push(`Watch for common issues: ${profile.commonIssues.join(', ')}`);
      }
    }

    return { profile, patterns, tips };
  }
}

// Singleton instance
let envAgentInstance: EnvironmentAnalysisAgent | null = null;

export function getEnvironmentAnalysisAgent(): EnvironmentAnalysisAgent {
  if (!envAgentInstance) {
    envAgentInstance = new EnvironmentAnalysisAgent();
  }
  return envAgentInstance;
}
