import * as React from "react";
import { HistoryChartProps, ChartDataPoint } from "./HistoryChart.models";
import HistoryChartView from "./HistoryChart.view";
import { ReportPeriod } from "../../features/report";

type DecoratedPeriod = ReportPeriod & {
  id: string;
  label: string;
};

const TAB_TO_KEY: Record<string, "weekly" | "monthly" | "yearly" | "fyly"> = {
  Weekly: "weekly",
  Monthly: "monthly",
  Yearly: "yearly",
  FYLY: "fyly"
};

function getAmount(p: ReportPeriod, mode: "expense" | "income") {
  return mode === "expense" ? p.expenses.sum : p.incomes.sum;
}

function mergeMetric(a: any, b: any) {
  const sum = a.sum + b.sum;
  const count = a.count + b.count;

  return {
    ...a,
    sum,
    count,
    average: count > 0 ? sum / count : 0,
    transactions: a.transactions || b.transactions
      ? [
          ...(a.transactions || []),
          ...(b.transactions || [])
        ]
      : undefined
  };
}

function mergeBuckets(
  buckets: any[],
  key: "weekly" | "monthly" | "yearly" | "fyly"
): DecoratedPeriod[] {
  const map = new Map<string, DecoratedPeriod>();

  for (const bucket of buckets) {
    const periods = (bucket.periods[key] || []) as DecoratedPeriod[];

    for (const p of periods) {
      const existing = map.get(p.id);

      if (!existing) {
        map.set(p.id, {
          ...p,
          expenses: { ...p.expenses },
          incomes: { ...p.incomes }
        });
      } else {
        map.set(p.id, {
          ...existing,
          expenses: mergeMetric(existing.expenses, p.expenses),
          incomes: mergeMetric(existing.incomes, p.incomes)
        });
      }
    }
  }

  return Array.from(map.values()).sort(
    (a, b) => new Date(a.start).getTime() - new Date(b.start).getTime()
  );
}

function attachComparison(
  points: ChartDataPoint[],
  key: "weekly" | "monthly" | "yearly" | "fyly"
): ChartDataPoint[] {
  const getCompareIndex = (i: number) => {
    if (key === "weekly") return i - 4;
    if (key === "monthly") return i - 12;
    if (key === "yearly") return i - 1;
    if (key === "fyly") return i - 1;
    return -1;
  };

  return points.map((p, i) => {
    const ci = getCompareIndex(i);

    return {
      ...p,
      compare:
        ci >= 0 && points[ci]
          ? {
              id: points[ci].id,
              label: points[ci].label,
              amount: points[ci].amount
            }
          : undefined
    };
  });
}

function buildChartData(
  reportData: HistoryChartProps["reportData"],
  key: "weekly" | "monthly" | "yearly" | "fyly",
  mode: "expense" | "income",
  comparison: boolean
): ChartDataPoint[] {
  const merged = mergeBuckets(reportData.buckets, key);
  console.log("Merged periods:", merged);

  let points: ChartDataPoint[] = merged.map((p) => ({
    id: p.id,
    label: p.label,
    amount: getAmount(p, mode)
  }));

  if (comparison) {
    points = attachComparison(points, key);
  }

  return points;
}

export default function HistoryChart(props: HistoryChartProps) {
  const {
    tabs,
    reportData,
    mode,
    periodType,
    comparison,
    selectedPeriodId,
    setSelectedPeriodId
  } = props;

  const [activeTab, setActiveTab] = React.useState<string>(tabs[0] || "");
  const [startIndex, setStartIndex] = React.useState(0);

  const activeDataKey = TAB_TO_KEY[activeTab];

  const currentData = React.useMemo(() => {
    return buildChartData(reportData, activeDataKey, mode, comparison);
  }, [reportData, activeDataKey, mode, comparison]);

  const maxAmount =
    currentData.length > 0
      ? Math.max(
          ...currentData.flatMap((d) =>
            comparison
              ? [d.amount, ...(d.compare ? [d.compare.amount] : [])]
              : [d.amount]
          ),
          1
        )
      : 1;

  const visibleCountMap = {
    weekly: 6,
    monthly: 4,
    yearly: 4,
    fyly: 4
  };

  const visibleCount = visibleCountMap[activeDataKey] ?? 4;

  const total = currentData.length;

  const clampedStartIndex = Math.min(
    startIndex,
    Math.max(total - visibleCount, 0)
  );

  React.useEffect(() => {
    if (startIndex !== clampedStartIndex) {
      setStartIndex(clampedStartIndex);
    }
  }, [startIndex, clampedStartIndex]);

  const visibleData = currentData.slice(
    clampedStartIndex,
    clampedStartIndex + visibleCount
  );

  React.useEffect(() => {
    setSelectedPeriodId(null);
  }, [activeTab, periodType]);

  React.useEffect(() => {
    if (
      selectedPeriodId &&
      !visibleData.some((p) => p.id === selectedPeriodId)
    ) {
      setSelectedPeriodId(null);
    }
  }, [visibleData, selectedPeriodId]);

  return (
    <HistoryChartView
      {...props}
      activeTab={activeTab}
      setActiveTab={setActiveTab}
      currentData={currentData}
      visibleData={visibleData}
      maxAmount={maxAmount}
      visibleCount={visibleCount}
      startIndex={clampedStartIndex}
      setStartIndex={setStartIndex}
      activeDataKey={activeDataKey}
    />
  );
}
