import React, { useMemo, useState } 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 { Card, CardContent, CardHeader, CardTitle, CardAction } from "./card";
import { Empty, EmptyDescription } from "./empty";
import { Skeleton } from "./skeleton";
import { cn } from "@/lib/utils";
import {
  FALLBACK_TICK,
  FALLBACK_PRIMARY,
  FALLBACK_SECONDARY,
  FALLBACK_BG,
  FALLBACK_NEUTRAL,
  formatAbbrev,
  formatTooltipDate,
  formatMonthLabel,
  ChartPeriodButton,
} from "./chart-shared";

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

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

export type PropertyPeriod = 1 | 3 | 5 | 10;

export interface PropertyEstimateDataPoint {
  /** ISO date string e.g. "2024-01-01" */
  date: string;
  /** Property estimate value in dollars */
  estimateValue: number;
  /** Suburb average price in dollars */
  suburbAverage: number;
  /**
   * Outstanding debt in dollars.
   * Optional — when provided, a third "Debt" line is rendered.
   * Used in the property estimate + debt combined view (backoffice / property detail).
   */
  debt?: number;
}

export interface PropertyMobileEstimateLineChartProps {
  chartData?: PropertyEstimateDataPoint[] | null;
  title?: string;
  /** Show or hide the chart legend */
  showLegend?: boolean;
  /** Legend placement relative to the chart */
  legendPosition?: "top" | "bottom";
  /** Show or hide X axis labels */
  showXAxis?: boolean;
  /** Show or hide Y axis labels */
  showYAxis?: boolean;
  /** Default year period selector value */
  defaultPeriod?: PropertyPeriod;
  /**
   * Show or hide the 1Y / 3Y / 5Y / 10Y period selector buttons.
   * Set to false for dashboard/summary contexts where a fixed view is preferred.
   * Defaults to true (mobile property detail use case).
   */
  showPeriodSelector?: boolean;
  /**
   * Which year periods to show as selector buttons. Defaults to [1, 3, 5, 10].
   * Pass a subset (e.g. [5, 10]) to match a specific surface — the dashboard
   * property card shows only 5Y / 10Y.
   */
  periods?: PropertyPeriod[];
  /** Chart canvas height in pixels */
  height?: number;
  /** Card max-width in pixels or CSS string */
  width?: number | string;
  className?: string;
  /** Show skeleton loading state instead of the chart */
  isLoading?: boolean;
}

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

const PROPERTY_PERIODS: PropertyPeriod[] = [1, 3, 5, 10];

/** Approx monthly data points per year period */
const PROPERTY_SLICE_COUNT: Record<PropertyPeriod, number> = {
  1: 12,
  3: 36,
  5: 60,
  10: 120,
};

// ---------------------------------------------------------------------------
// Legend
// ---------------------------------------------------------------------------

interface LegendItemProps {
  label: string;
  color: string;
  lineWidth: number;
  dashed?: boolean;
}

function LegendItem({
  label,
  color,
  lineWidth,
  dashed = false,
}: LegendItemProps) {
  return (
    <div className="flex items-center gap-1.5">
      <div
        style={{
          width: 24,
          height: lineWidth,
          flexShrink: 0,
          ...(dashed
            ? {
                backgroundImage: `repeating-linear-gradient(90deg, ${color} 0px, ${color} 5px, transparent 5px, transparent 9px)`,
              }
            : { backgroundColor: color }),
        }}
      />
      <span className="text-[11px] text-muted-foreground leading-none">
        {label}
      </span>
    </div>
  );
}

function ChartLegend({
  primaryColor,
  secondaryColor,
  showDebt,
}: {
  primaryColor: string;
  secondaryColor: string;
  showDebt: boolean;
}) {
  return (
    <div className="flex flex-wrap gap-x-3 gap-y-1.5 pb-2">
      <LegendItem label="Estimate Value" color={primaryColor} lineWidth={2.5} />
      <LegendItem
        label="Suburb Average"
        color={FALLBACK_NEUTRAL}
        lineWidth={1.5}
        dashed={showDebt}
      />
      {showDebt && (
        <LegendItem label="Debt" color={secondaryColor} lineWidth={2} />
      )}
    </div>
  );
}

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

export function PropertyMobileEstimateLineChart({
  chartData,
  title = "Property Estimate",
  showLegend = true,
  legendPosition = "top",
  showXAxis = true,
  showYAxis = false,
  defaultPeriod = 1,
  showPeriodSelector = true,
  periods = PROPERTY_PERIODS,
  height = 200,
  width = "100%",
  className,
  isLoading = false,
}: PropertyMobileEstimateLineChartProps) {
  const [period, setPeriod] = useState<PropertyPeriod>(defaultPeriod);

  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<PropertyEstimateDataPoint[] | null>(() => {
    if (!chartData?.length) return null;
    const count = Math.min(PROPERTY_SLICE_COUNT[period], chartData.length);
    const start = chartData.length - count;
    return chartData.slice(start);
  }, [chartData, period]);

  /** True when at least one data point has a debt value */
  const showDebt = useMemo(
    () => !!sliced?.some((p) => p.debt != null && p.debt > 0),
    [sliced],
  );

  const labels = useMemo(
    () => sliced?.map((p) => formatMonthLabel(p.date)) ?? [],
    [sliced],
  );

  const data = useMemo<ChartData<"line">>(() => {
    if (!sliced) return { labels: [], datasets: [] };
    return {
      labels,
      datasets: [
        {
          label: "Estimate Value",
          data: sliced.map((p) => p.estimateValue),
          borderColor: brandPrimary,
          backgroundColor: "transparent",
          borderWidth: 2.5,
          tension: 0.4,
          pointRadius: 0,
          pointHoverRadius: 6,
          pointHoverBackgroundColor: FALLBACK_BG,
          pointHoverBorderColor: brandPrimary,
          pointHoverBorderWidth: 3,
          pointHitRadius: 10,
          fill: false,
        },
        {
          label: "Suburb Average",
          data: sliced.map((p) => p.suburbAverage),
          borderColor: FALLBACK_NEUTRAL,
          backgroundColor: "transparent",
          ...(showDebt ? { borderDash: [4, 4] } : {}),
          borderWidth: 1.5,
          tension: 0.4,
          pointRadius: 0,
          pointHoverRadius: 5,
          pointHoverBackgroundColor: FALLBACK_BG,
          pointHoverBorderColor: FALLBACK_NEUTRAL,
          pointHoverBorderWidth: 2,
          pointHitRadius: 10,
          fill: false,
        },
        ...(showDebt
          ? [
              {
                label: "Debt",
                data: sliced.map((p) => p.debt ?? 0),
                borderColor: brandSecondary,
                backgroundColor: "transparent",
                borderWidth: 2,
                tension: 0.4,
                pointRadius: 0,
                pointHoverRadius: 5,
                pointHoverBackgroundColor: FALLBACK_BG,
                pointHoverBorderColor: brandSecondary,
                pointHoverBorderWidth: 2,
                pointHitRadius: 10,
                fill: false,
              },
            ]
          : []),
      ],
    };
  }, [sliced, labels, brandPrimary, brandSecondary, showDebt]);

  const options = useMemo<ChartOptions<"line">>(
    () => ({
      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?.[idx]?.date) {
                return formatTooltipDate(sliced[idx].date, "monthly");
              }
              return tooltipItems[0]?.label ?? "";
            },
            label: (ctx) => {
              const val = ctx.raw as number;
              if (val === 0) return;
              return ` ${ctx.dataset.label}: ${formatAbbrev(val)}`;
            },
          },
        },
      },
      scales: {
        x: {
          display: showXAxis,
          grid: { display: false },
          border: { display: false },
          ticks: {
            maxRotation: 0,
            minRotation: 0,
            color: FALLBACK_TICK,
            font: { size: 12, family: fontFamily },
            maxTicksLimit: 12,
          },
        },
        y: {
          display: showYAxis,
          position: "left",
          grid: { display: false },
          border: { display: false },
          ticks: {
            padding: 8,
            maxTicksLimit: 5,
            color: FALLBACK_TICK,
            font: { size: 12, family: fontFamily },
            callback: (v) => formatAbbrev(Number(v)),
          },
        },
      },
    }),
    [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)}
                  unit="Y"
                />
              ))}
            </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
                primaryColor={brandPrimary}
                secondaryColor={brandSecondary}
                showDebt={showDebt}
              />
            )}
            <div style={{ height, width: "100%", position: "relative" }}>
              <Chart
                key={`${brandPrimary}__${brandSecondary}`}
                type="line"
                data={data}
                options={options}
                aria-label={title}
              />
            </div>
            {showLegend && legendPosition === "bottom" && (
              <ChartLegend
                primaryColor={brandPrimary}
                secondaryColor={brandSecondary}
                showDebt={showDebt}
              />
            )}
          </div>
        )}
      </CardContent>
    </Card>
  );
}
