/**
 * Data Aggregator for Analytics
 * Aggregates data from various sources for analytics dashboards
 */

import {
  AnalyticsOverview,
  PlantAnalytics,
  TransportAnalytics,
  FarmAnalytics,
  SustainabilityAnalytics,
  TimeRange,
  DateRange,
  TimeSeriesDataPoint,
  AnalyticsFilters,
  AggregationConfig,
  GroupByPeriod,
} from './types';
import { subDays, subMonths, startOfDay, endOfDay, format, eachDayOfInterval, parseISO } from 'date-fns';

// Mock data generators for demonstration - in production these would query actual databases

/**
 * Get date range from TimeRange enum
 */
export function getDateRangeFromTimeRange(timeRange: TimeRange): DateRange {
  const end = endOfDay(new Date());
  let start: Date;

  switch (timeRange) {
    case '7d':
      start = startOfDay(subDays(new Date(), 7));
      break;
    case '30d':
      start = startOfDay(subDays(new Date(), 30));
      break;
    case '90d':
      start = startOfDay(subDays(new Date(), 90));
      break;
    case '365d':
      start = startOfDay(subDays(new Date(), 365));
      break;
    case 'all':
    default:
      start = startOfDay(subMonths(new Date(), 24)); // Default to 2 years
  }

  return { start, end };
}

/**
 * Generate time series data points for a date range
 */
export function generateTimeSeriesPoints(
  dateRange: DateRange,
  valueGenerator: (date: Date, index: number) => number
): TimeSeriesDataPoint[] {
  const days = eachDayOfInterval({ start: dateRange.start, end: dateRange.end });
  return days.map((day, index) => ({
    timestamp: format(day, 'yyyy-MM-dd'),
    value: valueGenerator(day, index),
    label: format(day, 'MMM d'),
  }));
}

/**
 * Aggregate data by time period
 */
export function aggregateByPeriod<T>(
  data: T[],
  dateField: keyof T,
  valueField: keyof T,
  period: GroupByPeriod
): Record<string, number> {
  const aggregated: Record<string, number> = {};

  data.forEach((item) => {
    const date = parseISO(item[dateField] as string);
    let key: string;

    switch (period) {
      case 'hour':
        key = format(date, 'yyyy-MM-dd HH:00');
        break;
      case 'day':
        key = format(date, 'yyyy-MM-dd');
        break;
      case 'week':
        key = format(date, "yyyy-'W'ww");
        break;
      case 'month':
        key = format(date, 'yyyy-MM');
        break;
      case 'year':
        key = format(date, 'yyyy');
        break;
    }

    aggregated[key] = (aggregated[key] || 0) + (item[valueField] as number);
  });

  return aggregated;
}

/**
 * Calculate percentage change between two values
 */
export function calculateChange(current: number, previous: number): { change: number; percent: number } {
  const change = current - previous;
  const percent = previous !== 0 ? (change / previous) * 100 : current > 0 ? 100 : 0;
  return { change, percent };
}

/**
 * Get analytics overview with aggregated metrics
 */
export async function getAnalyticsOverview(
  filters: AnalyticsFilters = { timeRange: '30d' }
): Promise<AnalyticsOverview> {
  const dateRange = filters.dateRange || getDateRangeFromTimeRange(filters.timeRange);

  // In production, these would be actual database queries
  // For now, generate realistic mock data
  const baseValue = 1000 + Math.random() * 500;

  return {
    totalPlants: Math.floor(baseValue * 1.5),
    plantsRegisteredToday: Math.floor(Math.random() * 15 + 5),
    plantsRegisteredThisWeek: Math.floor(Math.random() * 80 + 40),
    plantsRegisteredThisMonth: Math.floor(Math.random() * 250 + 150),
    totalTransportEvents: Math.floor(baseValue * 2.3),
    totalCarbonKg: Math.round((Math.random() * 500 + 200) * 100) / 100,
    totalFoodMiles: Math.round((Math.random() * 10000 + 5000) * 10) / 10,
    activeUsers: Math.floor(Math.random() * 200 + 100),
    growthRate: Math.round((Math.random() * 20 + 5) * 10) / 10,
    trendsData: [
      {
        metric: 'Plants',
        currentValue: Math.floor(baseValue * 1.5),
        previousValue: Math.floor(baseValue * 1.35),
        change: Math.floor(baseValue * 0.15),
        changePercent: 11.1,
        direction: 'up',
        period: filters.timeRange,
      },
      {
        metric: 'Carbon Saved',
        currentValue: Math.round((Math.random() * 200 + 100) * 10) / 10,
        previousValue: Math.round((Math.random() * 180 + 90) * 10) / 10,
        change: Math.round((Math.random() * 20 + 10) * 10) / 10,
        changePercent: 12.5,
        direction: 'up',
        period: filters.timeRange,
      },
      {
        metric: 'Active Users',
        currentValue: Math.floor(Math.random() * 200 + 100),
        previousValue: Math.floor(Math.random() * 180 + 90),
        change: Math.floor(Math.random() * 30 + 10),
        changePercent: 8.3,
        direction: 'up',
        period: filters.timeRange,
      },
      {
        metric: 'Food Miles',
        currentValue: Math.round((Math.random() * 5000 + 2500) * 10) / 10,
        previousValue: Math.round((Math.random() * 5500 + 2800) * 10) / 10,
        change: -Math.round((Math.random() * 500 + 200) * 10) / 10,
        changePercent: -8.7,
        direction: 'down',
        period: filters.timeRange,
      },
    ],
  };
}

/**
 * Get plant-specific analytics
 */
export async function getPlantAnalytics(
  filters: AnalyticsFilters = { timeRange: '30d' }
): Promise<PlantAnalytics> {
  const dateRange = filters.dateRange || getDateRangeFromTimeRange(filters.timeRange);

  const speciesData = [
    { species: 'Tomato', count: 245, percentage: 28.5, trend: 'up' as const },
    { species: 'Lettuce', count: 198, percentage: 23.0, trend: 'up' as const },
    { species: 'Pepper', count: 156, percentage: 18.1, trend: 'stable' as const },
    { species: 'Basil', count: 134, percentage: 15.6, trend: 'up' as const },
    { species: 'Cucumber', count: 87, percentage: 10.1, trend: 'down' as const },
    { species: 'Other', count: 41, percentage: 4.7, trend: 'stable' as const },
  ];

  return {
    totalPlants: speciesData.reduce((sum, s) => sum + s.count, 0),
    plantsBySpecies: speciesData,
    plantsByGeneration: [
      { generation: 1, count: 340, percentage: 39.5 },
      { generation: 2, count: 280, percentage: 32.5 },
      { generation: 3, count: 156, percentage: 18.1 },
      { generation: 4, count: 68, percentage: 7.9 },
      { generation: 5, count: 17, percentage: 2.0 },
    ],
    registrationsTrend: generateTimeSeriesPoints(dateRange, (_, i) =>
      Math.floor(Math.random() * 15 + 5 + Math.sin(i / 7) * 5)
    ),
    averageLineageDepth: 2.3,
    topGrowers: [
      { userId: 'user-1', name: 'Green Gardens Co', totalPlants: 145, totalSpecies: 12, averageGeneration: 2.1 },
      { userId: 'user-2', name: 'Urban Farm LLC', totalPlants: 98, totalSpecies: 8, averageGeneration: 1.8 },
      { userId: 'user-3', name: 'Local Seeds Inc', totalPlants: 76, totalSpecies: 15, averageGeneration: 3.2 },
    ],
    recentRegistrations: [
      { id: 'plant-1', name: 'Cherry Tomato #245', species: 'Tomato', registeredAt: new Date().toISOString(), generation: 3 },
      { id: 'plant-2', name: 'Butterhead Lettuce', species: 'Lettuce', registeredAt: new Date().toISOString(), generation: 2 },
      { id: 'plant-3', name: 'Sweet Basil', species: 'Basil', registeredAt: new Date().toISOString(), generation: 1 },
    ],
  };
}

/**
 * Get transport analytics
 */
export async function getTransportAnalytics(
  filters: AnalyticsFilters = { timeRange: '30d' }
): Promise<TransportAnalytics> {
  const dateRange = filters.dateRange || getDateRangeFromTimeRange(filters.timeRange);

  return {
    totalEvents: 2847,
    totalDistanceKm: 15234.5,
    totalCarbonKg: 487.3,
    carbonSavedKg: 1256.8,
    eventsByType: [
      { eventType: 'seed_acquisition', count: 423, percentage: 14.9, carbonKg: 52.3 },
      { eventType: 'growing_transport', count: 687, percentage: 24.1, carbonKg: 112.4 },
      { eventType: 'harvest', count: 534, percentage: 18.8, carbonKg: 45.2 },
      { eventType: 'distribution', count: 756, percentage: 26.6, carbonKg: 178.9 },
      { eventType: 'consumer_delivery', count: 447, percentage: 15.7, carbonKg: 98.5 },
    ],
    eventsByMethod: [
      { method: 'walking', count: 312, percentage: 11.0, distanceKm: 156, carbonKg: 0, efficiency: 100 },
      { method: 'bicycle', count: 534, percentage: 18.8, distanceKm: 1602, carbonKg: 0, efficiency: 100 },
      { method: 'electric_vehicle', count: 687, percentage: 24.1, distanceKm: 4806, carbonKg: 72.1, efficiency: 85 },
      { method: 'gasoline_vehicle', count: 756, percentage: 26.6, distanceKm: 5292, carbonKg: 264.6, efficiency: 45 },
      { method: 'local_delivery', count: 558, percentage: 19.6, distanceKm: 3378, carbonKg: 150.6, efficiency: 60 },
    ],
    dailyStats: generateTimeSeriesPoints(dateRange, (_, i) => ({
      date: format(dateRange.start, 'yyyy-MM-dd'),
      eventCount: Math.floor(Math.random() * 80 + 40),
      distanceKm: Math.round((Math.random() * 500 + 200) * 10) / 10,
      carbonKg: Math.round((Math.random() * 20 + 5) * 100) / 100,
    })).map(p => ({
      date: p.timestamp,
      eventCount: p.value,
      distanceKm: Math.round((Math.random() * 500 + 200) * 10) / 10,
      carbonKg: Math.round((Math.random() * 20 + 5) * 100) / 100,
    })),
    averageDistancePerEvent: 5.35,
    mostEfficientRoutes: [
      { from: 'Local Farm A', to: 'Community Center', method: 'bicycle', distanceKm: 2.3, carbonKg: 0, frequency: 45 },
      { from: 'Urban Garden', to: 'Farmers Market', method: 'walking', distanceKm: 0.8, carbonKg: 0, frequency: 38 },
      { from: 'Rooftop Farm', to: 'Restaurant Row', method: 'electric_vehicle', distanceKm: 4.5, carbonKg: 0.07, frequency: 32 },
    ],
    carbonTrend: generateTimeSeriesPoints(dateRange, (_, i) =>
      Math.round((Math.random() * 15 + 10 - i * 0.1) * 100) / 100
    ),
  };
}

/**
 * Get farm analytics
 */
export async function getFarmAnalytics(
  filters: AnalyticsFilters = { timeRange: '30d' }
): Promise<FarmAnalytics> {
  const dateRange = filters.dateRange || getDateRangeFromTimeRange(filters.timeRange);

  return {
    totalFarms: 24,
    totalZones: 156,
    activeBatches: 89,
    completedBatches: 234,
    averageYieldKg: 45.6,
    resourceUsage: {
      waterLiters: 125000,
      energyKwh: 8500,
      nutrientsKg: 450,
      waterEfficiency: 87.5,
      energyEfficiency: 92.3,
    },
    performanceByZone: [
      { zoneId: 'zone-1', zoneName: 'Zone A - Leafy Greens', currentCrop: 'Lettuce', healthScore: 94, yieldKg: 52.3, efficiency: 91 },
      { zoneId: 'zone-2', zoneName: 'Zone B - Herbs', currentCrop: 'Basil', healthScore: 88, yieldKg: 38.7, efficiency: 85 },
      { zoneId: 'zone-3', zoneName: 'Zone C - Tomatoes', currentCrop: 'Cherry Tomato', healthScore: 92, yieldKg: 67.4, efficiency: 89 },
      { zoneId: 'zone-4', zoneName: 'Zone D - Microgreens', currentCrop: 'Mixed Micro', healthScore: 96, yieldKg: 24.1, efficiency: 94 },
    ],
    batchCompletionTrend: generateTimeSeriesPoints(dateRange, (_, i) =>
      Math.floor(Math.random() * 5 + 2)
    ),
    yieldPredictions: [
      { cropType: 'Lettuce', predictedYieldKg: 156.5, confidence: 0.92, harvestDate: format(subDays(new Date(), -7), 'yyyy-MM-dd') },
      { cropType: 'Tomato', predictedYieldKg: 234.8, confidence: 0.87, harvestDate: format(subDays(new Date(), -14), 'yyyy-MM-dd') },
      { cropType: 'Basil', predictedYieldKg: 45.2, confidence: 0.94, harvestDate: format(subDays(new Date(), -5), 'yyyy-MM-dd') },
    ],
    topPerformingCrops: [
      { cropType: 'Lettuce', averageYieldKg: 48.3, growthDays: 28, successRate: 94.5, batches: 45 },
      { cropType: 'Basil', averageYieldKg: 12.4, growthDays: 21, successRate: 91.2, batches: 38 },
      { cropType: 'Cherry Tomato', averageYieldKg: 67.8, growthDays: 65, successRate: 88.7, batches: 22 },
      { cropType: 'Microgreens', averageYieldKg: 5.6, growthDays: 14, successRate: 96.8, batches: 67 },
    ],
  };
}

/**
 * Get sustainability analytics
 */
export async function getSustainabilityAnalytics(
  filters: AnalyticsFilters = { timeRange: '30d' }
): Promise<SustainabilityAnalytics> {
  const dateRange = filters.dateRange || getDateRangeFromTimeRange(filters.timeRange);

  return {
    overallScore: 82.5,
    carbonFootprint: {
      totalEmittedKg: 487.3,
      totalSavedKg: 1256.8,
      netImpactKg: -769.5,
      reductionPercentage: 72.1,
      equivalentTrees: 38.4,
      monthlyTrend: generateTimeSeriesPoints(dateRange, (_, i) =>
        Math.round((50 - i * 0.5 + Math.random() * 10) * 10) / 10
      ),
    },
    foodMiles: {
      totalMiles: 15234.5,
      averageMilesPerPlant: 17.7,
      savedMiles: 48672.3,
      localPercentage: 76.2,
      monthlyTrend: generateTimeSeriesPoints(dateRange, (_, i) =>
        Math.round((600 - i * 5 + Math.random() * 100) * 10) / 10
      ),
    },
    waterUsage: {
      totalUsedLiters: 125000,
      savedLiters: 87500,
      efficiencyScore: 87.5,
      perKgProduce: 2.8,
    },
    localProduction: {
      localCount: 654,
      totalCount: 861,
      percentage: 76.0,
      trend: 'up',
    },
    goals: [
      { id: 'goal-1', name: 'Carbon Neutral by 2025', target: 0, current: 487.3, unit: 'kg CO2', progress: 72, deadline: '2025-12-31', status: 'on_track' },
      { id: 'goal-2', name: '80% Local Production', target: 80, current: 76, unit: '%', progress: 95, deadline: '2024-12-31', status: 'on_track' },
      { id: 'goal-3', name: 'Reduce Food Miles 50%', target: 50, current: 38, unit: '%', progress: 76, deadline: '2024-06-30', status: 'at_risk' },
      { id: 'goal-4', name: 'Water Efficiency 90%', target: 90, current: 87.5, unit: '%', progress: 97, deadline: '2024-12-31', status: 'on_track' },
    ],
    trends: [
      {
        metric: 'Carbon Reduction',
        values: generateTimeSeriesPoints(dateRange, (_, i) =>
          Math.round((65 + i * 0.3 + Math.random() * 5) * 10) / 10
        ),
      },
      {
        metric: 'Local Production',
        values: generateTimeSeriesPoints(dateRange, (_, i) =>
          Math.round((70 + i * 0.2 + Math.random() * 3) * 10) / 10
        ),
      },
    ],
  };
}

/**
 * Cache management for analytics data
 */
const analyticsCache = new Map<string, { data: any; timestamp: number }>();
const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes

export function getCachedData<T>(key: string): T | null {
  const cached = analyticsCache.get(key);
  if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) {
    return cached.data as T;
  }
  return null;
}

export function setCachedData<T>(key: string, data: T): void {
  analyticsCache.set(key, { data, timestamp: Date.now() });
}

export function clearCache(): void {
  analyticsCache.clear();
}

/**
 * Generate cache key from filters
 */
export function generateCacheKey(prefix: string, filters: AnalyticsFilters): string {
  return `${prefix}-${JSON.stringify(filters)}`;
}
