// src/features/charts/PriceHistoryChart.tsx
import React, { useState, useEffect, useMemo } from 'react';
import {
  LineChart,
  Line,
  XAxis,
  YAxis,
  CartesianGrid,
  Tooltip,
  Legend,
  ResponsiveContainer,
} from 'recharts';
import * as apiClient from '../../services/apiClient';
import { LoadingSpinner } from '../../components/LoadingSpinner'; // This path is correct
import { useUserData } from '../../hooks/useUserData';
import type { HistoricalPriceDataPoint } from '../../types';

type HistoricalData = Record<string, { date: string; price: number }[]>;
type ChartData = { date: string; [itemName: string]: number | string };

const COLORS = ['#10B981', '#3B82F6', '#F59E0B', '#EF4444', '#8B5CF6', '#EC4899'];

export const PriceHistoryChart: React.FC = () => {
  const { watchedItems, isLoading: isLoadingUserData } = useUserData();
  const [historicalData, setHistoricalData] = useState<HistoricalData>({});
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const watchedItemsMap = useMemo(
    () => new Map(watchedItems.map((item) => [item.master_grocery_item_id, item.name])),
    [watchedItems],
  );

  useEffect(() => {
    if (watchedItems.length === 0) {
      setIsLoading(false);
      setHistoricalData({}); // Clear data if watchlist becomes empty
      return;
    }

    const fetchData = async () => {
      setIsLoading(true);
      setError(null);
      try {
        const watchedItemIds = watchedItems
          .map((item) => item.master_grocery_item_id)
          .filter((id): id is number => id !== undefined); // Ensure only numbers are passed
        const response = await apiClient.fetchHistoricalPriceData(watchedItemIds);
        const rawData: HistoricalPriceDataPoint[] = await response.json();
        if (rawData.length === 0) {
          setHistoricalData({});
          return;
        }

        const processedData = rawData.reduce<HistoricalData>(
          (acc, record: HistoricalPriceDataPoint) => {
            if (
              !record.master_item_id ||
              record.avg_price_in_cents === null ||
              !record.summary_date
            )
              return acc;

            const itemName = watchedItemsMap.get(record.master_item_id);
            if (!itemName) return acc;

            const priceInCents = record.avg_price_in_cents;
            const date = new Date(`${record.summary_date}T00:00:00`).toLocaleDateString('en-US', {
              month: 'short',
              day: 'numeric',
            });

            if (priceInCents === 0) return acc;

            if (!acc[itemName]) {
              acc[itemName] = [];
            }

            // Ensure we only store the LOWEST price for a given day
            const existingEntryIndex = acc[itemName].findIndex((entry) => entry.date === date);
            if (existingEntryIndex > -1) {
              if (priceInCents < acc[itemName][existingEntryIndex].price) {
                acc[itemName][existingEntryIndex].price = priceInCents;
              }
            } else {
              acc[itemName].push({ date, price: priceInCents });
            }

            return acc;
          },
          {},
        );

        // Filter out items that only have one data point for a meaningful trend line
        const filteredData = Object.entries(processedData).reduce<HistoricalData>(
          (acc, [key, value]) => {
            if (value.length > 1) {
              acc[key] = value.sort(
                (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime(),
              );
            }
            return acc;
          },
          {},
        );

        setHistoricalData(filteredData);
      } catch (e) {
        // This is a type-safe way to handle errors. We check if the caught
        // object is an instance of Error before accessing its message property.
        setError(e instanceof Error ? e.message : 'Failed to load price history.');
      } finally {
        setIsLoading(false);
      }
    };
    fetchData();
  }, [watchedItems, watchedItemsMap]);

  const chartData = useMemo<ChartData[]>(() => {
    const availableItems = Object.keys(historicalData);
    if (availableItems.length === 0) return [];

    const dateMap: Map<string, ChartData> = new Map();

    availableItems.forEach((itemName) => {
      historicalData[itemName]?.forEach(({ date, price }) => {
        if (!dateMap.has(date)) {
          dateMap.set(date, { date });
        }
        // Store price in cents
        dateMap.get(date)![itemName] = price;
      });
    });

    return Array.from(dateMap.values()).sort(
      (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime(),
    );
  }, [historicalData]);

  const availableItems = Object.keys(historicalData);

  const renderContent = () => {
    if (isLoading || isLoadingUserData) {
      return (
        <div role="status" className="flex justify-center items-center h-full min-h-50]">
          <LoadingSpinner /> <span className="ml-2">Loading Price History...</span>
        </div>
      );
    }

    if (error) {
      return (
        <div
          className="bg-red-100 dark:bg-red-900/50 border border-red-400 dark:border-red-600 text-red-700 dark:text-red-300 px-4 py-3 rounded-lg relative h-full flex items-center justify-center"
          role="alert"
        >
          <p>
            <strong>Error:</strong> {error}
          </p>
        </div>
      );
    }

    if (watchedItems.length === 0) {
      return (
        <div className="text-center py-8 h-full flex flex-col justify-center">
          <p className="text-gray-500 dark:text-gray-400">
            Add items to your watchlist to see their price trends over time.
          </p>
        </div>
      );
    }

    if (availableItems.length === 0) {
      return (
        <div className="text-center py-8 h-full flex flex-col justify-center">
          <p className="text-gray-500 dark:text-gray-400">
            Not enough historical data for your watched items. Process more flyers to build a trend.
          </p>
        </div>
      );
    }

    return (
      <ResponsiveContainer>
        <LineChart data={chartData} margin={{ top: 5, right: 20, left: -10, bottom: 5 }}>
          <CartesianGrid strokeDasharray="3 3" stroke="rgba(128, 128, 128, 0.2)" />
          <XAxis dataKey="date" tick={{ fill: '#9CA3AF', fontSize: 12 }} />
          <YAxis
            tick={{ fill: '#9CA3AF', fontSize: 12 }}
            tickFormatter={(value: number) => `$${(value / 100).toFixed(2)}`}
            domain={[(a: number) => Math.floor(a * 0.95), (b: number) => Math.ceil(b * 1.05)]}
          />
          <Tooltip
            contentStyle={{
              backgroundColor: 'rgba(31, 41, 55, 0.9)',
              border: '1px solid #4B5563',
              borderRadius: '0.5rem',
            }}
            labelStyle={{ color: '#F9FAFB' }}
            formatter={(value: number | undefined) => {
              if (typeof value === 'number') {
                return [`$${(value / 100).toFixed(2)}`];
              }
              return [null];
            }}
          />
          <Legend wrapperStyle={{ fontSize: '12px' }} />
          {availableItems.map((item, index) => (
            <Line
              key={item}
              type="monotone"
              dataKey={item}
              stroke={COLORS[index % COLORS.length]}
              strokeWidth={2}
              dot={{ r: 4 }}
              connectNulls
            />
          ))}
        </LineChart>
      </ResponsiveContainer>
    );
  };

  return (
    <div className="bg-white dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700 p-4">
      <h3 className="text-lg font-semibold mb-4 text-gray-800 dark:text-white">
        Historical Price Trends
      </h3>
      <div style={{ width: '100%', height: 300 }}>{renderContent()}</div>
    </div>
  );
};
