/**
 * Demand to Harvest Integration Tests
 * Tests the complete flow from demand signal to plant to harvest
 */

import { TransportChain, setTransportChain } from '../../lib/transport/tracker';
import { DemandForecaster } from '../../lib/demand/forecaster';
import {
  ConsumerPreference,
  PlantingRecommendation,
} from '../../lib/demand/types';
import {
  SeedAcquisitionEvent,
  PlantingEvent,
  HarvestEvent,
  DistributionEvent,
  ConsumerDeliveryEvent,
  TransportLocation,
} from '../../lib/transport/types';

describe('Demand to Harvest Integration', () => {
  let chain: TransportChain;
  let forecaster: DemandForecaster;

  beforeEach(() => {
    chain = new TransportChain(1);
    setTransportChain(chain);
    forecaster = new DemandForecaster();
  });

  describe('Complete Demand-Driven Flow', () => {
    it('should complete full flow from demand to consumer delivery', () => {
      // Step 1: Register consumer demand
      const consumerId = 'consumer-integration-001';
      const pref: ConsumerPreference = {
        consumerId,
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString(),
        location: {
          latitude: 40.7128,
          longitude: -74.006,
          maxDeliveryRadiusKm: 25,
          city: 'New York',
        },
        dietaryType: ['omnivore'],
        allergies: [],
        dislikes: [],
        preferredCategories: ['leafy_greens'],
        preferredItems: [
          { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 5, seasonalOnly: false },
        ],
        certificationPreferences: ['organic', 'local'],
        freshnessImportance: 5,
        priceImportance: 3,
        sustainabilityImportance: 5,
        deliveryPreferences: {
          method: ['home_delivery'],
          frequency: 'weekly',
          preferredDays: ['saturday'],
        },
        householdSize: 4,
        weeklyBudget: 100,
        currency: 'USD',
      };

      forecaster.registerPreference(pref);

      // Step 2: Generate demand signal
      const signal = forecaster.generateDemandSignal(
        40.7128, -74.006, 50, 'NYC Metro', 'spring'
      );

      expect(signal.totalConsumers).toBe(1);
      expect(signal.demandItems.length).toBeGreaterThan(0);
      const lettuceItem = signal.demandItems.find(i => i.produceType === 'lettuce');
      expect(lettuceItem).toBeDefined();
      expect(lettuceItem!.weeklyDemandKg).toBe(20); // 5 kg * 4 household size

      // Step 3: Generate planting recommendation for grower
      const recommendations = forecaster.generatePlantingRecommendations(
        'grower-integration-001',
        40.72, -74.01, // Near NYC
        50, // 50km delivery radius
        100, // 100 sqm available
        'spring'
      );

      expect(recommendations.length).toBeGreaterThan(0);
      const lettuceRec = recommendations.find(r => r.produceType === 'lettuce');
      expect(lettuceRec).toBeDefined();

      // Step 4: Grower follows recommendation and plants
      const seedBatchId = 'demand-driven-batch-001';
      const plantIds = ['demand-plant-001', 'demand-plant-002'];

      const seedEvent: SeedAcquisitionEvent = {
        id: 'demand-seed-001',
        timestamp: new Date().toISOString(),
        eventType: 'seed_acquisition',
        fromLocation: createLocation('seed_bank', 'Local Organic Seeds'),
        toLocation: createLocation('greenhouse', 'Grower Greenhouse'),
        distanceKm: 10,
        durationMinutes: 20,
        transportMethod: 'electric_vehicle',
        carbonFootprintKg: 0,
        senderId: 'seed-supplier',
        receiverId: 'grower-integration-001',
        status: 'verified',
        seedBatchId,
        sourceType: 'purchase',
        species: 'Lactuca sativa',
        variety: 'Butterhead',
        quantity: 100,
        quantityUnit: 'seeds',
        generation: 1,
        certifications: ['organic'],
      };

      chain.recordEvent(seedEvent);

      const plantingEvent: PlantingEvent = {
        id: 'demand-planting-001',
        timestamp: new Date(Date.now() + 1000).toISOString(),
        eventType: 'planting',
        fromLocation: createLocation('greenhouse', 'Grower Greenhouse'),
        toLocation: createLocation('greenhouse', 'Grower Greenhouse'),
        distanceKm: 0,
        durationMinutes: 30,
        transportMethod: 'walking',
        carbonFootprintKg: 0,
        senderId: 'grower-integration-001',
        receiverId: 'grower-integration-001',
        status: 'verified',
        seedBatchId,
        plantIds,
        plantingMethod: 'indoor_start',
        quantityPlanted: plantIds.length,
        growingEnvironment: 'greenhouse',
        expectedHarvestDate: new Date(Date.now() + 45 * 24 * 60 * 60 * 1000).toISOString(),
      };

      chain.recordEvent(plantingEvent);

      // Step 5: Harvest
      const harvestBatchId = 'demand-harvest-batch-001';

      const harvestEvent: HarvestEvent = {
        id: 'demand-harvest-001',
        timestamp: new Date(Date.now() + 45 * 24 * 60 * 60 * 1000).toISOString(),
        eventType: 'harvest',
        fromLocation: createLocation('greenhouse', 'Grower Greenhouse'),
        toLocation: createLocation('hub', 'Distribution Hub'),
        distanceKm: 5,
        durationMinutes: 15,
        transportMethod: 'electric_vehicle',
        carbonFootprintKg: 0,
        senderId: 'grower-integration-001',
        receiverId: 'hub-distribution',
        status: 'verified',
        plantIds,
        harvestBatchId,
        harvestType: 'full',
        produceType: 'Butterhead Lettuce',
        grossWeight: 2,
        netWeight: 1.8,
        weightUnit: 'kg',
        qualityGrade: 'A',
        packagingType: 'sustainable_boxes',
        temperatureRequired: { min: 2, max: 8, optimal: 4, unit: 'celsius' },
        shelfLifeHours: 168,
        seedsSaved: false,
      };

      chain.recordEvent(harvestEvent);

      // Step 6: Distribution
      const distributionEvent: DistributionEvent = {
        id: 'demand-distribution-001',
        timestamp: new Date(Date.now() + 46 * 24 * 60 * 60 * 1000).toISOString(),
        eventType: 'distribution',
        fromLocation: createLocation('hub', 'Distribution Hub'),
        toLocation: createLocation('market', 'Local Delivery Zone'),
        distanceKm: 10,
        durationMinutes: 20,
        transportMethod: 'electric_truck',
        carbonFootprintKg: 0,
        senderId: 'hub-distribution',
        receiverId: 'delivery-service',
        status: 'verified',
        batchIds: [harvestBatchId],
        destinationType: 'consumer',
        customerType: 'individual',
        deliveryWindow: {
          start: new Date(Date.now() + 46 * 24 * 60 * 60 * 1000).toISOString(),
          end: new Date(Date.now() + 46.5 * 24 * 60 * 60 * 1000).toISOString(),
        },
        deliveryAttempts: 1,
        handoffVerified: true,
      };

      chain.recordEvent(distributionEvent);

      // Step 7: Consumer Delivery
      const deliveryEvent: ConsumerDeliveryEvent = {
        id: 'demand-delivery-001',
        timestamp: new Date(Date.now() + 46.25 * 24 * 60 * 60 * 1000).toISOString(),
        eventType: 'consumer_delivery',
        fromLocation: createLocation('market', 'Local Delivery Zone'),
        toLocation: createLocation('consumer', 'Consumer Home'),
        distanceKm: 3,
        durationMinutes: 10,
        transportMethod: 'electric_vehicle',
        carbonFootprintKg: 0,
        senderId: 'delivery-service',
        receiverId: consumerId,
        status: 'verified',
        orderId: 'order-integration-001',
        batchIds: [harvestBatchId],
        deliveryMethod: 'home_delivery',
        finalMileMethod: 'electric_vehicle',
        packagingReturned: true,
        feedbackReceived: true,
        feedbackRating: 5,
        feedbackNotes: 'Fresh and delicious!',
      };

      chain.recordEvent(deliveryEvent);

      // Verify complete chain
      expect(chain.isChainValid()).toBe(true);
      expect(chain.chain.length).toBe(7); // Genesis + 6 events

      // Verify plant journey
      const journey = chain.getPlantJourney(plantIds[0]);
      expect(journey).not.toBeNull();
      expect(journey!.events.length).toBe(3); // planting, harvest, and possibly more

      // Verify environmental impact
      const impact = chain.getEnvironmentalImpact('grower-integration-001');
      expect(impact.totalFoodMiles).toBeLessThan(50); // Local delivery
      expect(impact.comparisonToConventional.percentageReduction).toBeGreaterThan(0);
    });
  });

  describe('Supply Registration Affects Recommendations', () => {
    it('should adjust recommendations based on existing supply', () => {
      // Register high demand
      const pref = createConsumerPreference('consumer-001');
      pref.preferredItems = [
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 100, seasonalOnly: false },
      ];
      pref.householdSize = 1;
      forecaster.registerPreference(pref);

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

      // Get recommendations without supply
      const recsWithoutSupply = forecaster.generatePlantingRecommendations(
        'grower-001', 40.7, -74.0, 50, 100, 'spring'
      );

      // Register significant supply
      forecaster.registerSupply({
        id: 'supply-001',
        growerId: 'other-grower',
        timestamp: new Date().toISOString(),
        produceType: 'lettuce',
        committedQuantityKg: 80,
        availableFrom: new Date().toISOString(),
        availableUntil: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
        pricePerKg: 5,
        currency: 'USD',
        minimumOrderKg: 1,
        certifications: ['organic'],
        freshnessGuaranteeHours: 48,
        deliveryRadiusKm: 50,
        deliveryMethods: ['grower_delivery'],
        status: 'available',
        remainingKg: 80,
      });

      // Generate new demand signal (with supply factored in)
      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'spring');

      // Get recommendations with supply
      const recsWithSupply = forecaster.generatePlantingRecommendations(
        'grower-001', 40.7, -74.0, 50, 100, 'spring'
      );

      // Recommendations should be different (less space recommended for lettuce)
      if (recsWithoutSupply.length > 0 && recsWithSupply.length > 0) {
        const lettuceWithout = recsWithoutSupply.find(r => r.produceType === 'lettuce');
        const lettuceWith = recsWithSupply.find(r => r.produceType === 'lettuce');

        if (lettuceWithout && lettuceWith) {
          expect(lettuceWith.recommendedQuantity).toBeLessThanOrEqual(lettuceWithout.recommendedQuantity);
        }
      }
    });
  });

  describe('Regional Demand Matching', () => {
    it('should match growers with regional demand', () => {
      // Create consumers in different regions
      const nycConsumer = createConsumerPreference('nyc-consumer');
      nycConsumer.location = { latitude: 40.7128, longitude: -74.006, maxDeliveryRadiusKm: 10 };
      forecaster.registerPreference(nycConsumer);

      const laConsumer = createConsumerPreference('la-consumer');
      laConsumer.location = { latitude: 34.0522, longitude: -118.2437, maxDeliveryRadiusKm: 10 };
      forecaster.registerPreference(laConsumer);

      // Generate signals for each region
      const nycSignal = forecaster.generateDemandSignal(40.7128, -74.006, 20, 'NYC', 'spring');
      const laSignal = forecaster.generateDemandSignal(34.0522, -118.2437, 20, 'LA', 'spring');

      expect(nycSignal.totalConsumers).toBe(1);
      expect(laSignal.totalConsumers).toBe(1);

      // NYC grower should only see NYC demand
      const nycGrowerRecs = forecaster.generatePlantingRecommendations(
        'nyc-grower', 40.72, -74.01, 25, 100, 'spring'
      );

      // LA grower should only see LA demand
      const laGrowerRecs = forecaster.generatePlantingRecommendations(
        'la-grower', 34.06, -118.25, 25, 100, 'spring'
      );

      // Both should have recommendations from their respective regions
      expect(nycGrowerRecs.length + laGrowerRecs.length).toBeGreaterThanOrEqual(0);
    });
  });

  describe('Seasonal Demand Flow', () => {
    it('should respect seasonal availability in recommendations', () => {
      const pref = createConsumerPreference('seasonal-consumer');
      pref.preferredItems = [
        { produceType: 'tomato', category: 'nightshades', priority: 'must_have', weeklyQuantity: 5, seasonalOnly: false },
        { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 5, seasonalOnly: false },
      ];
      forecaster.registerPreference(pref);

      // Winter recommendations
      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'winter');
      const winterRecs = forecaster.generatePlantingRecommendations(
        'grower-001', 40.7, -74.0, 50, 100, 'winter'
      );

      // Tomato should not be recommended in winter (not in season)
      const tomatoWinter = winterRecs.find(r => r.produceType === 'tomato');
      expect(tomatoWinter).toBeUndefined();

      // Summer recommendations
      forecaster.generateDemandSignal(40.7, -74.0, 50, 'Test', 'summer');
      const summerRecs = forecaster.generatePlantingRecommendations(
        'grower-001', 40.7, -74.0, 50, 100, 'summer'
      );

      // Tomato should be recommended in summer
      const tomatoSummer = summerRecs.find(r => r.produceType === 'tomato');
      expect(tomatoSummer).toBeDefined();
    });
  });
});

// Helper functions
function createLocation(type: string, name: string): TransportLocation {
  return {
    latitude: 40.7 + Math.random() * 0.1,
    longitude: -74.0 + Math.random() * 0.1,
    locationType: type as any,
    facilityName: name,
  };
}

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: [
      { produceType: 'lettuce', category: 'leafy_greens', priority: 'must_have', weeklyQuantity: 2, seasonalOnly: false },
    ],
    certificationPreferences: ['organic'],
    freshnessImportance: 4,
    priceImportance: 3,
    sustainabilityImportance: 4,
    deliveryPreferences: {
      method: ['home_delivery'],
      frequency: 'weekly',
      preferredDays: ['saturday'],
    },
    householdSize: 2,
    weeklyBudget: 100,
    currency: 'USD',
  };
}
