import React, { useMemo, useState } from "react";
import {
  Chart as ChartJS,
  CategoryScale,
  LinearScale,
  LineController,
  LineElement,
  PointElement,
  BarController,
  BarElement,
  Tooltip,
  type ChartOptions,
} from "chart.js";
import { Chart } from "react-chartjs-2";
import { BarChart2, LineChart } from "lucide-react";
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,
  hexToRgba,
  formatTooltipDate,
  formatMonthLabel,
  formatCount,
  ChartLegendItem,
  ChartPeriodButton,
} from "./chart-shared";
import { ToggleGroup, ToggleGroupItem } from "./toggle-group";

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

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

/**
 * One month of alert-matching data showing how many contacts fall into each
 * alert-status bucket.
 */
export interface AlertMatchingDataPoint {
  /** ISO date string e.g. "2024-01-01" */
  date: string;
  /** Contacts with no active alerts (healthy). */
  healthy: number;
  /** Contacts matching at least one Watch-level alert. */
  watch: number;
  /** Contacts matching at least one Need-Action alert. */
  needAction: number;
}

export type AlertMatchingPeriod = 3 | 6 | 12;
type AlertMatchingChartType = "line" | "bar";

export interface BackofficeAlertMatchingChartProps {
  chartData?: AlertMatchingDataPoint[] | null;
  title?: string;
  showLegend?: boolean;
  legendPosition?: "top" | "bottom";
  showXAxis?: boolean;
  showYAxis?: boolean;
  defaultPeriod?: AlertMatchingPeriod;
  height?: number;
  width?: number | string;
  className?: string;
  isLoading?: boolean;
}

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

const PERIODS: AlertMatchingPeriod[] = [3, 6, 12];
const SLICE_COUNT: Record<AlertMatchingPeriod, number> = { 3: 3, 6: 6, 12: 12 };

const HEALTHY_COLOR = "#166d42";
const WATCH_COLOR = "#EF6C00";
const NEED_ACTION_COLOR = "#F44336";

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

function AlertMatchingLegend() {
  return (
    <div className="flex flex-wrap gap-x-3 gap-y-1.5 pb-2">
      <ChartLegendItem
        label="Healthy"
        color={HEALTHY_COLOR}
        lineStyle="solid"
      />
      <ChartLegendItem label="Watch" color={WATCH_COLOR} lineStyle="solid" />
      <ChartLegendItem
        label="Need Action"
        color={NEED_ACTION_COLOR}
        lineStyle="solid"
      />
    </div>
  );
}

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

export function BackofficeAlertMatchingChart({
  chartData,
  title = "Alert Matching History",
  showLegend = true,
  legendPosition = "top",
  showXAxis = true,
  showYAxis = false,
  defaultPeriod = 6,
  height = 200,
  width = "100%",
  className,
  isLoading = false,
}: BackofficeAlertMatchingChartProps) {
  const [period, setPeriod] = useState<AlertMatchingPeriod>(defaultPeriod);
  const [chartType, setChartType] = useState<AlertMatchingChartType>("line");

  const themeVars = useThemeVars();
  const fontFamily: string =
    (themeVars["--font-sans"] as string | undefined) || "Figtree, sans-serif";

  const sliced = useMemo<AlertMatchingDataPoint[] | null>(() => {
    if (!chartData?.length) return null;
    const count = Math.min(SLICE_COUNT[period], chartData.length);
    return chartData.slice(chartData.length - count);
  }, [chartData, period]);

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

  const isBar = chartType === "bar";

  const datasets = useMemo(() => {
    if (!sliced) return [];
    return [
      {
        type: chartType,
        label: "Healthy",
        data: sliced.map((p) => p.healthy),
        borderColor: HEALTHY_COLOR,
        backgroundColor: isBar ? HEALTHY_COLOR : hexToRgba(HEALTHY_COLOR, 0.08),
        fill: !isBar,
        tension: 0.3,
        pointRadius: 0,
        borderWidth: 2,
      },
      {
        type: chartType,
        label: "Watch",
        data: sliced.map((p) => p.watch),
        borderColor: WATCH_COLOR,
        backgroundColor: isBar ? WATCH_COLOR : hexToRgba(WATCH_COLOR, 0.08),
        fill: !isBar,
        tension: 0.3,
        pointRadius: 0,
        borderWidth: 2,
      },
      {
        type: chartType,
        label: "Need Action",
        data: sliced.map((p) => p.needAction),
        borderColor: NEED_ACTION_COLOR,
        backgroundColor: isBar
          ? NEED_ACTION_COLOR
          : hexToRgba(NEED_ACTION_COLOR, 0.08),
        fill: !isBar,
        tension: 0.3,
        pointRadius: 0,
        borderWidth: 2,
      },
    ];
  }, [sliced, chartType, isBar]);

  const options = useMemo<ChartOptions<"bar">>(
    () => ({
      responsive: true,
      maintainAspectRatio: false,
      animation: { duration: 300 },
      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}: ${formatCount(val)}`;
            },
          },
        },
      },
      scales: {
        x: {
          display: showXAxis,
          grid: { display: false },
          border: { display: false },
          ticks: {
            maxRotation: 0,
            minRotation: 0,
            color: FALLBACK_TICK,
            font: { size: 10 },
          },
        },
        y: {
          display: showYAxis,
          grid: { display: false },
          border: { display: false },
          beginAtZero: true,
          ticks: {
            padding: 8,
            maxTicksLimit: 5,
            color: FALLBACK_TICK,
            font: { size: 10 },
            callback: (v) => formatCount(Number(v)),
          },
        },
      },
    }),
    [showXAxis, showYAxis, sliced],
  );

  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-wide">
          {title}
        </CardTitle>
        <CardAction>
          <div className="flex items-center gap-2">
            <ToggleGroup
              type="single"
              variant="outline"
              size="sm"
              value={[chartType]}
              onValueChange={(v) =>
                v[0] && setChartType(v[0] as AlertMatchingChartType)
              }
            >
              <ToggleGroupItem value="line" aria-label="Line chart">
                <LineChart className="size-3.5" />
              </ToggleGroupItem>
              <ToggleGroupItem value="bar" aria-label="Bar chart">
                <BarChart2 className="size-3.5" />
              </ToggleGroupItem>
            </ToggleGroup>
            <div className="flex gap-0.5 sm:gap-1">
              {PERIODS.map((p) => (
                <ChartPeriodButton
                  key={p}
                  period={p}
                  active={period === p}
                  onClick={() => setPeriod(p)}
                />
              ))}
            </div>
          </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" && <AlertMatchingLegend />}
            <div style={{ height, width: "100%", position: "relative" }}>
              {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
              <Chart
                key={chartType}
                type={chartType as any}
                data={{ labels, datasets } as any}
                options={options}
                aria-label={title}
              />
            </div>
            {showLegend && legendPosition === "bottom" && (
              <AlertMatchingLegend />
            )}
          </div>
        )}
      </CardContent>
    </Card>
  );
}
