/**
 * Recommendation Logic Tests
 * Tests for planting recommendation generation
 */

import {
  DemandForecaster,
} from '../../../lib/demand/forecaster';
import {
  ConsumerPreference,
  PlantingRecommendation,
  RiskFactor,
} from '../../../lib/demand/types';

describe('Planting Recommendations', () => {
  let forecaster: DemandForecaster;

  beforeEach(() => {
    forecaster = new DemandForecaster();
  });

  describe('Recommendation Generation', () => {
    it('should generate recommendations based on demand signals', () => {
      // Create demand
      const pref = createConsumerPreference('consumer-1');
      pref.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 10, seasonalOnly: false },
      ];
      pref.householdSize = 1;
      forecaster.registerPreference(pref);

      // Generate demand signal
      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test Region', 'spring');

      // Generate recommendations
      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1',
        40.7,
        -74.0,
        50,
        100, // 100 sqm available
        'spring'
      );

      expect(recommendations.length).toBeGreaterThan(0);
    });

    it('should include recommendation details', () => {
      const pref = createConsumerPreference('consumer-1');
      pref.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 10, seasonalOnly: false },
      ];
      forecaster.registerPreference(pref);

      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'spring');

      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1', 40.7, -74.0, 50, 100, 'spring'
      );

      const rec = recommendations[0];
      expect(rec.id).toBeDefined();
      expect(rec.growerId).toBe('grower-1');
      expect(rec.produceType).toBeDefined();
      expect(rec.recommendedQuantity).toBeGreaterThan(0);
      expect(rec.expectedYieldKg).toBeGreaterThan(0);
    });

    it('should not exceed available space', () => {
      const pref = createConsumerPreference('consumer-1');
      pref.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 1000, seasonalOnly: false },
      ];
      pref.householdSize = 1;
      forecaster.registerPreference(pref);

      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'spring');

      const availableSpace = 50; // Only 50 sqm
      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1', 40.7, -74.0, 50, availableSpace, 'spring'
      );

      const totalSpace = recommendations.reduce((sum, r) => sum + r.recommendedQuantity, 0);
      expect(totalSpace).toBeLessThanOrEqual(availableSpace);
    });

    it('should prioritize high-demand produce', () => {
      const pref = createConsumerPreference('consumer-1');
      pref.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 50, seasonalOnly: false },
        { produceType: 'spinach', category: 'leafy_greens', priority: 'occasional', weeklyQuantity: 5, seasonalOnly: false },
      ];
      pref.householdSize = 1;
      forecaster.registerPreference(pref);

      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'spring');

      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1', 40.7, -74.0, 50, 30, 'spring' // Limited space
      );

      // Should prioritize lettuce (high demand) over spinach
      if (recommendations.length > 0) {
        expect(recommendations[0].produceType).toBe('lettuce');
      }
    });
  });

  describe('Timing Calculations', () => {
    it('should include planting and harvest dates', () => {
      const pref = createConsumerPreference('consumer-1');
      pref.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 10, seasonalOnly: false },
      ];
      forecaster.registerPreference(pref);

      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'spring');

      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1', 40.7, -74.0, 50, 100, 'spring'
      );

      const rec = recommendations[0];
      expect(rec.plantByDate).toBeDefined();
      expect(rec.expectedHarvestStart).toBeDefined();
      expect(rec.expectedHarvestEnd).toBeDefined();
      expect(rec.growingDays).toBeGreaterThan(0);
    });

    it('should calculate harvest date based on growing days', () => {
      const pref = createConsumerPreference('consumer-1');
      pref.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 10, seasonalOnly: false },
      ];
      forecaster.registerPreference(pref);

      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'spring');

      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1', 40.7, -74.0, 50, 100, 'spring'
      );

      const rec = recommendations[0];
      const plantDate = new Date(rec.plantByDate);
      const harvestStart = new Date(rec.expectedHarvestStart);

      const daysDiff = (harvestStart.getTime() - plantDate.getTime()) / (1000 * 60 * 60 * 24);
      expect(daysDiff).toBeCloseTo(rec.growingDays, 0);
    });
  });

  describe('Financial Projections', () => {
    it('should calculate projected revenue', () => {
      const pref = createConsumerPreference('consumer-1');
      pref.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 10, seasonalOnly: false },
      ];
      pref.weeklyBudget = 100;
      forecaster.registerPreference(pref);

      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'spring');

      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1', 40.7, -74.0, 50, 100, 'spring'
      );

      const rec = recommendations[0];
      expect(rec.projectedPricePerKg).toBeGreaterThan(0);
      expect(rec.projectedRevenue).toBeGreaterThan(0);
      expect(rec.projectedRevenue).toBeCloseTo(
        rec.expectedYieldKg * rec.projectedPricePerKg,
        -1 // Allow some rounding
      );
    });

    it('should include market confidence', () => {
      const pref = createConsumerPreference('consumer-1');
      pref.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 10, seasonalOnly: false },
      ];
      forecaster.registerPreference(pref);

      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'spring');

      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1', 40.7, -74.0, 50, 100, 'spring'
      );

      const rec = recommendations[0];
      expect(rec.marketConfidence).toBeGreaterThanOrEqual(0);
      expect(rec.marketConfidence).toBeLessThanOrEqual(100);
    });
  });

  describe('Risk Assessment', () => {
    it('should include risk factors', () => {
      const pref = createConsumerPreference('consumer-1');
      pref.preferredItems = [
        { produceType: 'tomato', category: 'nightshades', priority: 'must_have', weeklyQuantity: 10, seasonalOnly: false },
      ];
      forecaster.registerPreference(pref);

      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'summer');

      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1', 40.7, -74.0, 50, 100, 'summer'
      );

      if (recommendations.length > 0) {
        const rec = recommendations[0];
        expect(rec.riskFactors).toBeDefined();
        expect(Array.isArray(rec.riskFactors)).toBe(true);
      }
    });

    it('should calculate overall risk level', () => {
      const pref = createConsumerPreference('consumer-1');
      pref.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 10, seasonalOnly: false },
      ];
      forecaster.registerPreference(pref);

      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'spring');

      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1', 40.7, -74.0, 50, 100, 'spring'
      );

      if (recommendations.length > 0) {
        const rec = recommendations[0];
        expect(['low', 'medium', 'high']).toContain(rec.overallRisk);
      }
    });

    it('should include risk mitigation suggestions', () => {
      const pref = createConsumerPreference('consumer-1');
      pref.preferredItems = [
        { produceType: 'tomato', category: 'nightshades', priority: 'must_have', weeklyQuantity: 100, seasonalOnly: false },
      ];
      forecaster.registerPreference(pref);

      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'summer');

      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1', 40.7, -74.0, 50, 10, 'summer' // Small space for large demand
      );

      if (recommendations.length > 0) {
        const rec = recommendations[0];
        rec.riskFactors.forEach(risk => {
          if (risk.mitigationSuggestion) {
            expect(typeof risk.mitigationSuggestion).toBe('string');
          }
        });
      }
    });
  });

  describe('Seasonal Filtering', () => {
    it('should only recommend in-season produce', () => {
      const pref = createConsumerPreference('consumer-1');
      pref.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 10, seasonalOnly: false },
        { produceType: 'tomato', category: 'nightshades', priority: 'must_have', weeklyQuantity: 10, seasonalOnly: false },
      ];
      forecaster.registerPreference(pref);

      // Winter - tomato is not in season
      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'winter');

      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1', 40.7, -74.0, 50, 100, 'winter'
      );

      // Tomato should not be recommended in winter
      const tomatoRec = recommendations.find(r => r.produceType === 'tomato');
      expect(tomatoRec).toBeUndefined();
    });
  });

  describe('Demand Signal Matching', () => {
    it('should filter signals by delivery radius', () => {
      // Consumer far from grower
      const pref = createConsumerPreference('consumer-1');
      pref.location = { latitude: 35.0, longitude: -80.0, maxDeliveryRadiusKm: 10 };
      pref.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 100, seasonalOnly: false },
      ];
      forecaster.registerPreference(pref);

      forecaster.generateDemandSignal(35.0, -80.0, 10, 'Distant Region', 'spring');

      // Grower is far from demand signal
      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1',
        40.7, // New York area
        -74.0,
        25, // Only 25km delivery radius
        100,
        'spring'
      );

      // Should have no recommendations because demand is too far
      expect(recommendations.length).toBe(0);
    });

    it('should match signals from multiple regions', () => {
      // Multiple consumers in nearby regions
      const pref1 = createConsumerPreference('consumer-1');
      pref1.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 10, seasonalOnly: false },
      ];
      forecaster.registerPreference(pref1);

      const pref2 = createConsumerPreference('consumer-2');
      pref2.location = { latitude: 40.72, longitude: -74.01, maxDeliveryRadiusKm: 25 };
      pref2.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 10, seasonalOnly: false },
      ];
      forecaster.registerPreference(pref2);

      forecaster.generateDemandSignal(40.7, -74.0, 20, 'Region 1', 'spring');
      forecaster.generateDemandSignal(40.75, -74.05, 20, 'Region 2', 'spring');

      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1', 40.7, -74.0, 50, 100, 'spring'
      );

      // Should aggregate demand from both regions
      expect(recommendations.length).toBeGreaterThan(0);
    });
  });

  describe('Yield Calculations', () => {
    it('should calculate expected yield based on area', () => {
      const pref = createConsumerPreference('consumer-1');
      pref.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 10, seasonalOnly: false },
      ];
      forecaster.registerPreference(pref);

      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'spring');

      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1', 40.7, -74.0, 50, 100, 'spring'
      );

      if (recommendations.length > 0) {
        const rec = recommendations[0];
        // Lettuce yields about 4 kg/sqm according to SEASONAL_DATA
        expect(rec.expectedYieldKg).toBeGreaterThan(0);
        expect(rec.yieldConfidence).toBeGreaterThan(0);
      }
    });

    it('should include yield confidence', () => {
      const pref = createConsumerPreference('consumer-1');
      pref.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 10, seasonalOnly: false },
      ];
      forecaster.registerPreference(pref);

      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'spring');

      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1', 40.7, -74.0, 50, 100, 'spring'
      );

      if (recommendations.length > 0) {
        const rec = recommendations[0];
        expect(rec.yieldConfidence).toBeGreaterThanOrEqual(0);
        expect(rec.yieldConfidence).toBeLessThanOrEqual(100);
      }
    });
  });

  describe('Explanation', () => {
    it('should include human-readable explanation', () => {
      const pref = createConsumerPreference('consumer-1');
      pref.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 10, seasonalOnly: false },
      ];
      forecaster.registerPreference(pref);

      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'spring');

      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1', 40.7, -74.0, 50, 100, 'spring'
      );

      if (recommendations.length > 0) {
        const rec = recommendations[0];
        expect(rec.explanation).toBeDefined();
        expect(rec.explanation.length).toBeGreaterThan(20);
        expect(rec.explanation).toContain('demand signal');
      }
    });

    it('should include demand signal IDs', () => {
      const pref = createConsumerPreference('consumer-1');
      pref.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 10, seasonalOnly: false },
      ];
      forecaster.registerPreference(pref);

      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'spring');

      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-1', 40.7, -74.0, 50, 100, 'spring'
      );

      if (recommendations.length > 0) {
        const rec = recommendations[0];
        expect(rec.demandSignalIds).toBeDefined();
        expect(rec.demandSignalIds.length).toBeGreaterThan(0);
      }
    });
  });
});

// Helper function
function createConsumerPreference(consumerId: string): ConsumerPreference {
  return {
    consumerId,
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    location: {
      latitude: 40.7128,
      longitude: -74.006,
      maxDeliveryRadiusKm: 25,
    },
    dietaryType: ['omnivore'],
    allergies: [],
    dislikes: [],
    preferredCategories: ['leafy_greens'],
    preferredItems: [],
    certificationPreferences: ['organic'],
    freshnessImportance: 4,
    priceImportance: 3,
    sustainabilityImportance: 4,
    deliveryPreferences: {
      method: ['home_delivery'],
      frequency: 'weekly',
      preferredDays: ['saturday'],
    },
    householdSize: 2,
    weeklyBudget: 100,
    currency: 'USD',
  };
}
