import React, { useRef, useEffect, useState } from 'react';
import { Line } from 'react-chartjs-2';
import ChartJS from 'chart.js/auto';
import zoomPlugin from 'chartjs-plugin-zoom';
import {
  getISOWeek,
  startOfDay,
  endOfDay,
  startOfWeek,
  endOfWeek,
  startOfMonth,
  endOfMonth,
  startOfYear,
  endOfYear,
} from 'date-fns';
import { fetchPowerTimeseries } from '@/app/utils/api';

ChartJS.register(zoomPlugin);

interface TimeSeriesEntry {
  time: string;
  value: number;
}

interface EnergyLineChartProps {
  siteId: string;
}

function groupTimeSeries(
  data: TimeSeriesEntry[],
  mode: 'day' | 'daily' | 'weekly' | 'monthly' | 'yearly'
): TimeSeriesEntry[] {
  const groupMap = new Map<string, number[]>();

  for (const entry of data) {
    const date = new Date(entry.time);
    let key = '';

    switch (mode) {
      case 'day':
        const local = new Date(date.toLocaleString('en-US', { timeZone: 'Asia/Kuala_Lumpur' }));
        const hour = local.getHours();
        const minute = local.getMinutes() < 30 ? '00' : '30';
        key = `${hour.toString().padStart(2, '0')}:${minute}`;
        break;
      case 'daily':
        key = date.toLocaleDateString('en-MY', {
          timeZone: 'Asia/Kuala_Lumpur',
          weekday: 'short',
          day: '2-digit',
          month: 'short',
        });
        break;
      case 'weekly':
        key = `${date.getFullYear()}-W${String(getISOWeek(date)).padStart(2, '0')}`;
        break;
      case 'monthly':
        key = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
        break;
      case 'yearly':
        key = date.getFullYear().toString();
        break;
    }

    if (!groupMap.has(key)) groupMap.set(key, []);
    groupMap.get(key)!.push(entry.value);
  }

  return Array.from(groupMap.entries()).map(([time, values]) => ({
    time,
    value: values.reduce((sum, v) => sum + v, 0),
  }));
}

const EnergyLineChart = ({ siteId }: EnergyLineChartProps) => {
  const chartRef = useRef<any>(null);
  const [viewMode, setViewMode] = useState<'day' | 'daily' | 'weekly' | 'monthly' | 'yearly'>('day');
  const [consumption, setConsumption] = useState<TimeSeriesEntry[]>([]);
  const [generation, setGeneration] = useState<TimeSeriesEntry[]>([]);
  const [selectedDate, setSelectedDate] = useState(new Date());

  useEffect(() => {
    const now = new Date();
    let start: Date;
    let end: Date;

    switch (viewMode) {
      case 'day':
        start = startOfDay(selectedDate);
        end = endOfDay(selectedDate);
        break;
      case 'daily':
        start = startOfWeek(now, { weekStartsOn: 1 });
        end = endOfWeek(now, { weekStartsOn: 1 });
        break;
      case 'weekly':
        start = startOfMonth(now);
        end = endOfMonth(now);
        break;
      case 'monthly':
        start = startOfYear(now);
        end = endOfYear(now);
        break;
      case 'yearly':
        start = new Date('2020-01-01');
        end = now;
        break;
    }

    const isoStart = start.toISOString();
    const isoEnd = end.toISOString();

    const fetchData = async () => {
      try {
        const res = await fetchPowerTimeseries(siteId, isoStart, isoEnd);
        setConsumption(res.consumption);
        setGeneration(res.generation);
      } catch (error) {
        console.error('Failed to fetch energy timeseries:', error);
      }
    };

    fetchData();
  }, [siteId, viewMode, selectedDate]);

  const groupedConsumption = groupTimeSeries(consumption, viewMode);
  const groupedGeneration = groupTimeSeries(generation, viewMode);

  const allTimes = Array.from(new Set([
    ...groupedConsumption.map(d => d.time),
    ...groupedGeneration.map(d => d.time),
  ])).sort();

  const consumptionMap = Object.fromEntries(groupedConsumption.map(d => [d.time, d.value]));
  const generationMap = Object.fromEntries(groupedGeneration.map(d => [d.time, d.value]));

  const [startIndex, setStartIndex] = useState(0);
  const [endIndex, setEndIndex] = useState(allTimes.length - 1);

  useEffect(() => {
    if (typeof window !== 'undefined') {
      import('hammerjs');
    }
  }, []);

  useEffect(() => {
    setStartIndex(0);
    setEndIndex(allTimes.length - 1);
  }, [viewMode, allTimes.length]);

  const formatLabel = (key: string) => {
    switch (viewMode) {
      case 'monthly':
        return new Date(`${key}-01`).toLocaleString('en-GB', { month: 'short', year: 'numeric' });
      case 'weekly':
        return key.replace('-', ' ');
      default:
        return key;
    }
  };

  const filteredLabels = allTimes.slice(startIndex, endIndex + 1);
  const filteredConsumption = filteredLabels.map(t => consumptionMap[t] ?? null);
  const filteredGeneration = filteredLabels.map(t => generationMap[t] ?? null);

  const allValues = [...filteredConsumption, ...filteredGeneration].filter(v => v !== null) as number[];
  const maxValue = allValues.length > 0 ? Math.max(...allValues) : 0;
  const yAxisSuggestedMax = maxValue * 1.15;

  const data = {
    labels: filteredLabels.map(formatLabel),
    datasets: [
      {
        label: 'Consumption',
        data: filteredConsumption,
        borderColor: '#8884d8',
        tension: 0.4,
        fill: false,
      },
      {
        label: 'Generation',
        data: filteredGeneration,
        borderColor: '#82ca9d',
        tension: 0.4,
        fill: false,
      },
    ],
  };

  const options = {
    responsive: true,
    maintainAspectRatio: false,
    plugins: {
      legend: { position: 'top' as const },
      zoom: {
        zoom: {
          wheel: { enabled: true },
          pinch: { enabled: true },
          mode: 'x' as const,
        },
        pan: { enabled: true, mode: 'x' as const },
      },
      tooltip: { enabled: true, mode: 'index' as const, intersect: false },
    },
    scales: {
      x: {
        title: {
          display: true,
          text:
            viewMode === 'day'
              ? 'Time (HH:MM)'
              : viewMode === 'daily'
              ? 'Day'
              : viewMode === 'weekly'
              ? 'Week'
              : viewMode === 'monthly'
              ? 'Month'
              : 'Year',
          font: { weight: 'bold' as const },
        },
      },
      y: {
        beginAtZero: true,
        suggestedMax: yAxisSuggestedMax,
        title: {
          display: true,
          text: 'Power (kW)',
          font: { weight: 'bold' as const },
        },
      },
    },
  } as const;

  const handleResetZoom = () => {
    chartRef.current?.resetZoom();
  };

  return (
    <div className="bg-white p-4 rounded-lg shadow-md dark:bg-gray-800 dark:text-white-light">
      <div className="h-98 w-full">
        <div className="flex justify-between items-center mb-2">
          <h2 className="text-lg font-bold dark:text-white-light">Energy Consumption & Generation</h2>
          <button onClick={handleResetZoom} className="btn-primary px-8 py-2 text-sm">
            Reset
          </button>
        </div>

        <div className="mb-4 flex gap-4 items-center">
          {viewMode === 'day' && (
            <label className="font-medium">
              Date:{' '}
              <input
                type="date"
                value={selectedDate.toISOString().split('T')[0]}
                onChange={(e) => setSelectedDate(new Date(e.target.value))}
                className="border rounded p-1"
              />
            </label>
          )}

          <label className="font-medium">
            From:{' '}
            <select
              value={startIndex}
              onChange={(e) => {
                const val = Number(e.target.value);
                setStartIndex(val <= endIndex ? val : endIndex);
              }}
              className="border rounded p-1"
            >
              {allTimes.map((label, idx) => (
                <option key={idx} value={idx}>{formatLabel(label)}</option>
              ))}
            </select>
          </label>
          <label className="font-medium">
            To:{' '}
            <select
              value={endIndex}
              onChange={(e) => {
                const val = Number(e.target.value);
                setEndIndex(val >= startIndex ? val : startIndex);
              }}
              className="border rounded p-1"
            >
              {allTimes.map((label, idx) => (
                <option key={idx} value={idx}>{formatLabel(label)}</option>
              ))}
            </select>
          </label>
          <label className="font-medium">
            View:{' '}
            <select
              value={viewMode}
              onChange={(e) => setViewMode(e.target.value as typeof viewMode)}
              className="border rounded p-1"
            >
              <option value="day">Day</option>
              <option value="daily">Daily</option>
              <option value="weekly">Weekly</option>
              <option value="monthly">Monthly</option>
              <option value="yearly">Yearly</option>
            </select>
          </label>
        </div>

        <div className="h-96 w-full">
          <Line ref={chartRef} data={data} options={options} />
        </div>
      </div>
    </div>
  );
};

export default EnergyLineChart;







