import React, { useMemo, useState } from "react";
import {
  Chart as ChartJS,
  CategoryScale,
  LinearScale,
  BarController,
  BarElement,
  Tooltip,
  Legend,
  type ChartOptions,
  type ChartData,
} from "chart.js";
import { Chart } from "react-chartjs-2";
import { useThemeVars } from "@/lib/theme-provider";
import { Card, CardContent, CardHeader, CardTitle, CardAction } from "./card";
import { Empty, EmptyDescription } from "./empty";
import { Skeleton } from "./skeleton";
import { cn } from "@/lib/utils";
import {
  hexToRgba,
  FALLBACK_TICK,
  FALLBACK_PRIMARY,
  FALLBACK_SECONDARY,
  formatTooltipDate,
  ChartPeriodButton,
} from "./chart-shared";

ChartJS.register(
  CategoryScale,
  LinearScale,
  BarController,
  BarElement,
  Tooltip,
  Legend,
);

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

export interface CashflowDataPoint {
  /** ISO date string e.g. "2024-01-01" */
  date: string;
  income: number;
  expenses: number;
  /** Positive value — ignored when overspending > 0 */
  surplus: number;
  /** Positive value — ignored when surplus > 0 */
  overspending: number;
}

export interface CashflowChartData {
  months: string[];
  data: CashflowDataPoint[];
}

export type CashflowPeriod = 3 | 6 | 12;

export interface CashflowBarChartProps {
  /** Full dataset — sliced to the selected period */
  cashflowData: CashflowChartData | null;
  title?: string;
  /** Show or hide the chart legend */
  showLegend?: boolean;
  /** Show or hide X axis labels */
  showXAxis?: boolean;
  /** Show or hide Y axis labels */
  showYAxis?: boolean;
  /** Legend placement relative to chart */
  legendPosition?: "top" | "bottom";
  /** Default period selector value */
  defaultPeriod?: CashflowPeriod;
  /** Show or hide the period selector buttons (3M / 6M / 12M) */
  showPeriodSelector?: boolean;
  /** Chart canvas height in pixels */
  height?: number;
  /** Width of the card in pixels */
  width?: number | string;
  className?: string;
  /** Show skeleton loading state instead of the chart */
  isLoading?: boolean;
}

// ---------------------------------------------------------------------------
// HTML legend (outside canvas — full spacing control)
// ---------------------------------------------------------------------------

interface LegendItemProps {
  label: string;
  fillColor: string;
  strokeColor: string;
  strokeWidth?: number;
}

function LegendItem({
  label,
  fillColor,
  strokeColor,
  strokeWidth = 1.5,
}: LegendItemProps) {
  return (
    <div className="flex items-center gap-1.5">
      <div
        style={{
          width: 10,
          height: 10,
          backgroundColor: fillColor,
          border:
            strokeWidth > 0 ? `${strokeWidth}px solid ${strokeColor}` : "none",
          flexShrink: 0,
        }}
      />
      <span className="text-[11px] text-muted-foreground leading-none">
        {label}
      </span>
    </div>
  );
}

function ChartLegend({
  primary,
  secondary,
}: {
  primary: string;
  secondary: string;
}) {
  return (
    <div className="flex flex-wrap gap-x-3 gap-y-1.5 pb-2">
      <LegendItem
        label="Income"
        fillColor={hexToRgba(primary, 0.2)}
        strokeColor={primary}
      />
      <LegendItem
        label="Expenses and Liabilities"
        fillColor={hexToRgba(secondary, 0.2)}
        strokeColor={secondary}
      />
      <LegendItem
        label="Surplus Income"
        fillColor={primary}
        strokeColor={primary}
        strokeWidth={0}
      />
      <LegendItem
        label="Over Spending"
        fillColor={secondary}
        strokeColor={secondary}
        strokeWidth={0}
      />
    </div>
  );
}

// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------

const PERIODS: CashflowPeriod[] = [3, 6, 12];

// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------

export function CashflowBarChart({
  cashflowData,
  title = "Cashflow",
  showLegend = true,
  showXAxis = true,
  showYAxis = true,
  legendPosition = "top",
  defaultPeriod = 6,
  showPeriodSelector = true,
  height = 280,
  width = "100%",
  className,
  isLoading = false,
}: CashflowBarChartProps) {
  const [period, setPeriod] = useState<CashflowPeriod>(defaultPeriod);

  // Read theme colors from ThemeProvider context.
  // Falls back to WealthX defaults when no ThemeProvider is present.
  const themeVars = useThemeVars();
  const brandPrimary: string =
    (themeVars["--theme-primary"] as string | undefined) || FALLBACK_PRIMARY;
  const brandSecondary: string =
    (themeVars["--theme-secondary"] as string | undefined) ||
    FALLBACK_SECONDARY;
  const fontFamily: string =
    (themeVars["--font-sans"] as string | undefined) || "Figtree, sans-serif";

  const sliced = useMemo<CashflowChartData | null>(() => {
    if (!cashflowData?.data?.length) return null;
    const count = Math.min(period, cashflowData.data.length);
    const start = cashflowData.data.length - count;
    return {
      months: cashflowData.months.slice(start),
      data: cashflowData.data.slice(start),
    };
  }, [cashflowData, period]);

  const chartData = useMemo<ChartData<"bar">>(() => {
    if (!sliced) return { labels: [], datasets: [] };

    return {
      labels: sliced.months,
      datasets: [
        {
          label: "Income",
          data: sliced.data.map((d) => d.income),
          backgroundColor: hexToRgba(brandPrimary, 0.2),
          hoverBackgroundColor: hexToRgba(brandPrimary, 0.35),
          borderColor: brandPrimary,
          borderWidth: 1.5,
          borderRadius: 0,
          borderSkipped: false,
          barPercentage: 0.75,
          categoryPercentage: 0.7,
        },
        {
          label: "Expenses and Liabilities",
          data: sliced.data.map((d) => d.expenses),
          backgroundColor: hexToRgba(brandSecondary, 0.2),
          hoverBackgroundColor: hexToRgba(brandSecondary, 0.35),
          borderColor: brandSecondary,
          borderWidth: 1.5,
          borderRadius: 0,
          borderSkipped: false,
          barPercentage: 0.75,
          categoryPercentage: 0.7,
        },
        {
          label: "_thirdBar",
          data: sliced.data.map((d) =>
            d.overspending > 0 ? d.overspending : d.surplus,
          ),
          backgroundColor: sliced.data.map((d) =>
            d.overspending > 0 ? brandSecondary : brandPrimary,
          ),
          hoverBackgroundColor: sliced.data.map((d) =>
            d.overspending > 0
              ? hexToRgba(brandSecondary, 0.8)
              : hexToRgba(brandPrimary, 0.8),
          ),
          borderWidth: 0,
          borderRadius: 0,
          borderSkipped: false,
          barPercentage: 0.75,
          categoryPercentage: 0.7,
        },
      ],
    };
  }, [sliced, brandPrimary, brandSecondary]);

  const options = useMemo<ChartOptions<"bar">>(
    () => ({
      responsive: true,
      maintainAspectRatio: false,
      animation: { duration: 800, easing: "easeOutQuart" },
      layout: { padding: 0 },
      plugins: {
        legend: { display: false },
        tooltip: {
          mode: "index",
          intersect: false,
          padding: 12,
          cornerRadius: 0,
          titleFont: { size: 11, weight: 600 },
          bodyFont: { size: 12, weight: 500 },
          callbacks: {
            title: (tooltipItems) => {
              const idx = tooltipItems[0]?.dataIndex;
              if (idx != null && sliced?.data[idx]?.date) {
                return formatTooltipDate(sliced.data[idx].date, "monthly");
              }
              return tooltipItems[0]?.label ?? "";
            },
            label: (ctx) => {
              const val = ctx.raw as number;
              if (val === 0) return;
              if (ctx.datasetIndex === 2) {
                const d = sliced?.data[ctx.dataIndex];
                if (!d) return;
                const lbl =
                  d.overspending > 0 ? "Over Spending" : "Surplus Income";
                return ` ${lbl}: $${val.toLocaleString()}`;
              }
              return ` ${ctx.dataset.label}: $${val.toLocaleString()}`;
            },
          },
        },
      },
      scales: {
        x: {
          display: showXAxis,
          grid: { display: false },
          border: { display: false },
          ticks: {
            font: { size: 12, family: fontFamily },
            color: FALLBACK_TICK,
          },
        },
        y: {
          display: showYAxis,
          grid: { display: false },
          border: { display: false },
          ticks: {
            font: { size: 12, family: fontFamily },
            color: FALLBACK_TICK,
            maxTicksLimit: 5,
            padding: 8,
            callback: (v) => `$${Number(v).toLocaleString()}`,
          },
        },
      },
    }),
    [showXAxis, showYAxis, sliced, fontFamily],
  );

  return (
    <Card
      className={cn("w-full py-4 sm:py-6 gap-2", className)}
      style={{ maxWidth: width, fontFamily }}
    >
      <CardHeader className="px-3 sm:px-6">
        <CardTitle className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
          {title}
        </CardTitle>
        {showPeriodSelector && (
          <CardAction>
            <div className="flex gap-0.5 sm:gap-1">
              {PERIODS.map((p) => (
                <ChartPeriodButton
                  key={p}
                  period={p}
                  active={period === p}
                  onClick={() => setPeriod(p)}
                />
              ))}
            </div>
          </CardAction>
        )}
      </CardHeader>

      <CardContent className="px-3 sm:px-6">
        {isLoading ? (
          <Skeleton style={{ height, width: "100%" }} />
        ) : !sliced ? (
          <Empty className="flex-none p-4" style={{ height }}>
            <EmptyDescription>No data available</EmptyDescription>
          </Empty>
        ) : (
          <div className="flex flex-col gap-2">
            {showLegend && legendPosition === "top" && (
              <ChartLegend primary={brandPrimary} secondary={brandSecondary} />
            )}
            <div style={{ height, width: "100%", position: "relative" }}>
              <Chart
                key={`${brandPrimary}__${brandSecondary}`}
                type="bar"
                data={chartData}
                options={options}
                aria-label={title}
              />
            </div>
            {showLegend && legendPosition === "bottom" && (
              <ChartLegend primary={brandPrimary} secondary={brandSecondary} />
            )}
          </div>
        )}
      </CardContent>
    </Card>
  );
}
