import React, { useMemo } from "react";
import {
  Chart as ChartJS,
  CategoryScale,
  LinearScale,
  LineController,
  LineElement,
  PointElement,
  Tooltip,
  type ChartOptions,
  type ChartData,
} from "chart.js";
import { Chart } from "react-chartjs-2";
import { useThemeVars } from "@/lib/theme-provider";
import {
  FALLBACK_TICK,
  FALLBACK_PRIMARY,
  FALLBACK_BG,
  FALLBACK_FOREGROUND,
  FALLBACK_GRID_COLOR,
  ChartLegendItem,
  formatAbbrev,
  formatMonthLabel,
  formatTooltipDate,
} from "./chart-shared";
import { Card, CardContent, CardHeader, CardTitle } from "./card";
import { Empty, EmptyDescription } from "./empty";
import { Skeleton } from "./skeleton";
import { cn } from "@/lib/utils";
import { formatCurrency } from "@/lib/format-currency";

ChartJS.register(
  CategoryScale,
  LinearScale,
  LineController,
  LineElement,
  PointElement,
  Tooltip,
);

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

export type BorrowingSeriesType =
  | "current-expenses"
  | "optimised-estimate"
  | "desired-loan-amount";

/** @deprecated use BorrowingSeriesType */
export type BorrowingScenario = BorrowingSeriesType;

export interface BorrowingCapacityDataPoint {
  /** ISO 8601 date string, e.g. "2025-01" or "2025-01-15" */
  date: string;
  /** Amount in AUD cents (avoids float precision issues) */
  amountCents: number;
}

export interface BorrowingCapacitySeries {
  type: BorrowingSeriesType;
  data: BorrowingCapacityDataPoint[];
}

export interface BorrowingCapacityLineChartProps {
  series?: BorrowingCapacitySeries[] | null;
  title?: string;
  /**
   * Current borrowing capacity in AUD cents — displayed as a KPI value
   * in the top-right corner of the card header.
   */
  kpiValue?: number;
  /** Chart canvas height in pixels */
  height?: number;
  /** Card max-width */
  width?: number | string;
  className?: string;
  /** Show skeleton loading state while data is in-flight */
  isLoading?: boolean;
  showXAxis?: boolean;
  showYAxis?: boolean;
  showLegend?: boolean;
  /** Legend placement relative to the chart */
  legendPosition?: "top" | "bottom";
}

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

const SERIES_LABELS: Record<BorrowingSeriesType, string> = {
  "current-expenses": "Based on Current Expenses",
  "optimised-estimate": "Optimised Estimate",
  "desired-loan-amount": "Desired Loan Amount",
};

const SERIES_LINE_STYLE: Record<BorrowingSeriesType, "solid" | "dashed"> = {
  "current-expenses": "solid",
  "optimised-estimate": "dashed",
  "desired-loan-amount": "dashed",
};

const SERIES_BORDER_WIDTH: Record<BorrowingSeriesType, number> = {
  "current-expenses": 2,
  "optimised-estimate": 1.5,
  "desired-loan-amount": 2,
};

/** Chart.js render order — reference line painted first (back), current expenses last (front). */
const SERIES_RENDER_ORDER: BorrowingSeriesType[] = [
  "desired-loan-amount",
  "optimised-estimate",
  "current-expenses",
];

/** Legend display order — left-to-right reading of the chart's primary-to-reference hierarchy. */
const SERIES_LEGEND_ORDER: BorrowingSeriesType[] = [
  "current-expenses",
  "optimised-estimate",
  "desired-loan-amount",
];

const DASH_PATTERN: number[] = [6, 4];

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

/** "2025-01" or "2025-01-15" → "Jan '25" for x-axis ticks */
function formatDateLabel(iso: string): string {
  const normalized = `${iso.slice(0, 7)}-01T00:00:00`;
  return formatMonthLabel(normalized);
}

/** "2025-01" → "Jan 2025" for tooltip header */
function formatDateTooltip(iso: string): string {
  const normalized = `${iso.slice(0, 7)}-01T00:00:00`;
  return formatTooltipDate(normalized, "monthly");
}

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

export function BorrowingCapacityLineChart({
  series,
  title = "Borrowing Capacity",
  kpiValue,
  height = 280,
  width = "100%",
  className,
  isLoading = false,
  showXAxis = true,
  showYAxis = true,
  showLegend = true,
  legendPosition = "bottom",
}: BorrowingCapacityLineChartProps) {
  const themeVars = useThemeVars();
  const brandPrimary =
    (themeVars["--theme-primary"] as string | undefined) || FALLBACK_PRIMARY;
  const fontFamily =
    (themeVars["--font-sans"] as string | undefined) || "Figtree, sans-serif";

  const seriesColor = useMemo<Record<BorrowingSeriesType, string>>(
    () => ({
      "current-expenses": FALLBACK_FOREGROUND,
      "optimised-estimate": FALLBACK_TICK,
      // desired-loan-amount tracks tenant brand; no alpha conversion needed at 1.0
      "desired-loan-amount": brandPrimary,
    }),
    [brandPrimary],
  );

  const orderedSeries = useMemo<BorrowingCapacitySeries[]>(() => {
    if (!series?.length) return [];
    return SERIES_RENDER_ORDER.map((t) =>
      series.find((s) => s.type === t),
    ).filter((s): s is BorrowingCapacitySeries => !!s && s.data.length > 0);
  }, [series]);

  const hasData = orderedSeries.length > 0;

  const labels = useMemo(() => {
    if (!orderedSeries.length) return [];
    const primary =
      orderedSeries.find((s) => s.type === "current-expenses") ??
      orderedSeries[0];
    return primary.data.map((p) => p.date);
  }, [orderedSeries]);

  const chartData = useMemo<ChartData<"line">>(() => {
    if (!orderedSeries.length) return { labels: [], datasets: [] };
    return {
      labels,
      datasets: orderedSeries.map((s) => {
        const color = seriesColor[s.type];
        const isDashed = SERIES_LINE_STYLE[s.type] === "dashed";
        return {
          label: SERIES_LABELS[s.type],
          data: s.data.map((p) => p.amountCents / 100),
          borderColor: color,
          backgroundColor: "transparent",
          borderWidth: SERIES_BORDER_WIDTH[s.type],
          borderDash: isDashed ? DASH_PATTERN : [],
          tension: s.type === "current-expenses" ? 0.4 : 0,
          pointRadius: 0,
          pointHoverRadius: s.type === "desired-loan-amount" ? 0 : 5,
          pointHoverBackgroundColor: FALLBACK_BG,
          pointHoverBorderColor: color,
          pointHoverBorderWidth: 2,
          pointHitRadius: 12,
        };
      }),
    };
  }, [labels, orderedSeries, seriesColor]);

  const options = useMemo<ChartOptions<"line">>(
    () => ({
      responsive: true,
      maintainAspectRatio: false,
      animation: { duration: 800, easing: "easeOutQuart" },
      plugins: {
        legend: { display: false },
        tooltip: {
          enabled: true,
          mode: "index",
          intersect: false,
          filter: (item) =>
            item.dataset.label !== SERIES_LABELS["desired-loan-amount"],
          displayColors: true,
          boxWidth: 10,
          boxHeight: 2,
          padding: 12,
          cornerRadius: 0,
          titleFont: { size: 11, weight: 600, family: fontFamily },
          bodyFont: { size: 12, weight: 500, family: fontFamily },
          callbacks: {
            title: (items) => {
              const iso = items[0]?.label;
              return iso ? formatDateTooltip(iso) : "";
            },
            label: (ctx) => {
              const dollars = ctx.parsed.y ?? 0;
              return ` ${ctx.dataset.label}: ${formatCurrency(dollars)}`;
            },
          },
        },
      },
      interaction: { mode: "index", intersect: false },
      scales: {
        x: {
          type: "category",
          display: showXAxis,
          grid: { display: false },
          border: { display: false },
          ticks: {
            autoSkip: true,
            maxTicksLimit: 7,
            maxRotation: 0,
            minRotation: 0,
            color: FALLBACK_TICK,
            font: { size: 12, family: fontFamily },
            callback: function (_, index) {
              const iso = labels[index];
              return iso ? formatDateLabel(iso) : "";
            },
          },
        },
        y: {
          display: showYAxis,
          position: "left",
          grid: { display: false },
          border: { display: false },
          ticks: {
            maxTicksLimit: 6,
            padding: 8,
            color: FALLBACK_TICK,
            font: { size: 12, family: fontFamily },
            callback: (v) => formatAbbrev(Number(v)),
          },
        },
      },
    }),
    [showXAxis, showYAxis, labels, fontFamily],
  );

  const legendEl = useMemo(() => {
    if (!showLegend || !hasData) return null;
    const items = SERIES_LEGEND_ORDER.map((t) =>
      orderedSeries.find((s) => s.type === t),
    ).filter((s): s is BorrowingCapacitySeries => !!s);
    return (
      <div className="flex flex-wrap items-center gap-x-4 gap-y-1.5">
        {items.map((s) => (
          <ChartLegendItem
            key={s.type}
            label={SERIES_LABELS[s.type]}
            color={seriesColor[s.type]}
            lineStyle={SERIES_LINE_STYLE[s.type]}
          />
        ))}
      </div>
    );
  }, [showLegend, hasData, orderedSeries, seriesColor]);

  const legendWrapper = legendEl ? (
    <div className={legendPosition === "top" ? "mb-3" : "mt-3"}>{legendEl}</div>
  ) : null;

  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">
        <div className="flex items-start justify-between gap-4">
          <CardTitle className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
            {title}
          </CardTitle>
          {kpiValue != null && (
            <span className="shrink-0 text-lg font-bold tabular-nums">
              {formatCurrency(kpiValue / 100)}
            </span>
          )}
        </div>
      </CardHeader>

      <CardContent className="px-3 sm:px-6">
        {isLoading ? (
          <Skeleton style={{ height, width: "100%" }} />
        ) : !hasData ? (
          <Empty className="flex-none p-4" style={{ height }}>
            <EmptyDescription>
              No borrowing capacity data available
            </EmptyDescription>
          </Empty>
        ) : (
          <>
            {legendPosition === "top" && legendWrapper}
            <div style={{ height, width: "100%", position: "relative" }}>
              <Chart
                type="line"
                data={chartData}
                options={options}
                aria-label={title}
              />
            </div>
            {legendPosition === "bottom" && legendWrapper}
          </>
        )}
      </CardContent>
    </Card>
  );
}
