"use client";

import * as React from "react";
import { BarChart3, PieChart as PieChartIcon } from "lucide-react";
import { Bar, BarChart, CartesianGrid, Cell, Pie, PieChart, XAxis, YAxis } from "recharts";

import {
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "@/components/ui/chart";
import { pieGeometryForSliceCount } from "@/lib/chart/positive-pie-slices";
import type { DriftAllocationComparison } from "@/app/customer/[tenant]/settings/_lib/tenant-settings-server-api";
import { cn } from "@/lib/utils";

import { DRIFT_RULE_COLORS } from "./drift-rule-colors";
import { DriftSection } from "./drift-ui-primitives";
import { orderByNest } from "./exclusive-rule-gaps";
import { formatDriftPct } from "./format-drift";

type SimulatedRuleRow = {
  rule_label: string;
  dimensions?: DriftAllocationComparison["dimensions"];
  ideal_pct: number;
  actual_pct: number;
  sim_actual_pct: number;
  is_virtual: boolean;
};

type AllocationChartsProps = {
  comparison: DriftAllocationComparison[];
  simRows?: SimulatedRuleRow[] | null;
  mode: "real" | "simulated";
  layout?: "full" | "compact";
};

type DonutRow = {
  name: string;
  value: number;
  isVirtual?: boolean;
  color?: string;
  depth?: number;
  dimensions?: DriftAllocationComparison["dimensions"];
};

type DonutLegendRow = DonutRow & {
  fill: string;
};

const BAR_SERIES_LABELS: Record<string, string> = {
  ideal: "Ideal",
  actual: "Actual",
  simulated: "Simulated",
};

function truncateAxisLabel(value: string, max = 16): string {
  const text = value.trim();
  if (text.length <= max) return text;
  return `${text.slice(0, max - 1)}…`;
}

function AllocationBarTooltip({
  active,
  payload,
  label,
}: {
  active?: boolean;
  payload?: Array<{ dataKey?: string | number; name?: string; value?: number | string; color?: string }>;
  label?: string;
}) {
  if (!active || !payload?.length) return null;

  return (
    <div className="grid min-w-[10rem] gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-2 text-xs shadow-xl">
      <div className="max-w-[220px] break-words font-medium text-foreground">{label}</div>
      <div className="grid gap-1">
        {payload.map((item) => {
          const key = String(item.dataKey ?? item.name ?? "");
          return (
            <div key={key} className="flex items-center justify-between gap-4">
              <span className="flex items-center gap-1.5 text-muted-foreground">
                <span
                  className="size-2.5 shrink-0 rounded-[2px]"
                  style={{ backgroundColor: item.color }}
                />
                {BAR_SERIES_LABELS[key] ?? key}
              </span>
              <span className="font-medium tabular-nums text-foreground">
                {formatDriftPct(Number(item.value))}
              </span>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function DonutSliceLegend({ rows }: { rows: DonutLegendRow[] }) {
  return (
    <ul className="w-full max-w-sm space-y-1.5 text-xs">
      {rows.map((row) => (
        <li
          key={row.name}
          className="flex items-center gap-2.5 rounded-lg border border-border/40 bg-card/60 py-1.5 pr-2.5"
          style={{ paddingLeft: `${10 + (row.depth ?? 0) * 16}px` }}
        >
          {(row.depth ?? 0) > 0 ? (
            <span
              className="w-3 shrink-0 border-b border-l border-border/70"
              style={{ height: "0.55rem" }}
              aria-hidden
            />
          ) : null}
          <span className="size-2.5 shrink-0 rounded-full" style={{ backgroundColor: row.fill }} />
          <span className="min-w-0 flex-1 truncate font-medium text-foreground/85" title={row.name}>
            {row.name}
          </span>
          <span className="shrink-0 tabular-nums font-semibold text-foreground">
            {formatDriftPct(row.value)}
          </span>
        </li>
      ))}
    </ul>
  );
}

function DriftAllocationDonut({
  data,
  config,
  resolveColor,
}: {
  data: DonutRow[];
  config: ChartConfig;
  resolveColor: (row: DonutRow, index: number) => string;
}) {
  const chartData = React.useMemo<DonutLegendRow[]>(() => {
    const withFill = data.map((row, index) => ({
      ...row,
      fill: resolveColor(row, index),
    }));
    const nestable = withFill.map((row) => ({
      rule_label: row.name,
      dimensions: row.dimensions,
    }));
    return orderByNest(nestable).map(({ depth, sourceIndex }) => ({
      ...withFill[sourceIndex]!,
      depth,
    }));
  }, [data, resolveColor]);
  const { paddingAngle, cornerRadius } = pieGeometryForSliceCount(chartData.length);

  if (!chartData.length) {
    return null;
  }

  return (
    <div className="flex flex-col items-center gap-4 sm:flex-row sm:items-center sm:justify-center sm:gap-6">
      <ChartContainer config={config} className="mx-auto aspect-square h-[220px] w-full max-w-[240px] shrink-0 sm:h-[240px]">
        <PieChart>
          <ChartTooltip
            content={
              <ChartTooltipContent
                hideLabel
                formatter={(value, _name, item) => {
                  const name = String(item?.payload?.name ?? _name ?? "");
                  return (
                    <div className="flex min-w-0 flex-col gap-0.5">
                      <span className="max-w-[220px] break-words text-foreground">{name}</span>
                      <span className="font-medium tabular-nums text-foreground/80">
                        {formatDriftPct(Number(value))}
                      </span>
                    </div>
                  );
                }}
                nameKey="name"
              />
            }
          />
          <Pie
            data={chartData}
            dataKey="value"
            nameKey="name"
            innerRadius={54}
            outerRadius={82}
            paddingAngle={paddingAngle}
            cornerRadius={cornerRadius}
            stroke="hsl(var(--card))"
            strokeWidth={2}
            isAnimationActive={false}
          >
            {chartData.map((row) => (
              <Cell key={row.name} fill={row.fill} className="stroke-background" />
            ))}
          </Pie>
        </PieChart>
      </ChartContainer>
      <DonutSliceLegend rows={chartData} />
    </div>
  );
}

export function AllocationCharts({ comparison, simRows, mode, layout }: AllocationChartsProps) {
  const resolvedLayout = layout ?? (mode === "simulated" ? "compact" : "full");

  const columnData = React.useMemo(() => {
    if (mode === "simulated" && simRows) {
      return simRows
        .filter((row) => !row.is_virtual)
        .map((row, index) => ({
          name: row.rule_label,
          ideal: row.ideal_pct,
          actual: row.actual_pct,
          simulated: row.sim_actual_pct,
          fill: DRIFT_RULE_COLORS[index % DRIFT_RULE_COLORS.length],
        }));
    }
    return comparison.map((row, index) => ({
      name: row.rule_label,
      ideal: row.ideal_pct,
      actual: row.actual_pct,
      fill: DRIFT_RULE_COLORS[index % DRIFT_RULE_COLORS.length],
    }));
  }, [comparison, mode, simRows]);

  const longAxisLabels = columnData.some((row) => row.name.length > 12);
  const manyCategories = columnData.length > 5;

  const actualDonutSource =
    mode === "simulated" && simRows
      ? simRows.map((row) => ({
          name: row.rule_label,
          value: Math.max(row.sim_actual_pct, 0),
          isVirtual: row.is_virtual,
          dimensions: row.dimensions,
        }))
      : comparison.map((row) => ({
          name: row.rule_label,
          value: Math.max(row.actual_pct, 0),
          isVirtual: false,
          dimensions: row.dimensions,
        }));

  const idealDonutSource = comparison.map((row, index) => ({
    name: row.rule_label,
    value: Math.max(row.ideal_pct, 0),
    isVirtual: false,
    color: DRIFT_RULE_COLORS[index % DRIFT_RULE_COLORS.length],
    dimensions: row.dimensions,
  }));

  const barConfig = {
    ideal: { label: "Ideal", color: "hsl(var(--chart-1))" },
    actual: { label: "Actual", color: "hsl(var(--chart-2))" },
    ...(mode === "simulated"
      ? { simulated: { label: "Simulated", color: "hsl(var(--chart-3))" } }
      : {}),
  } satisfies ChartConfig;

  const donutConfig = Object.fromEntries(
    actualDonutSource.map((row, index) => [
      row.name,
      {
        label: row.name,
        color: row.isVirtual ? "#f59e0b" : DRIFT_RULE_COLORS[index % DRIFT_RULE_COLORS.length],
      },
    ]),
  ) satisfies ChartConfig;

  const idealDonutConfig = Object.fromEntries(
    idealDonutSource.map((row) => [row.name, { label: row.name, color: row.color }]),
  ) satisfies ChartConfig;

  if (!columnData.length) {
    return <p className="py-8 text-center text-muted-foreground text-sm">No allocation rules to chart.</p>;
  }

  const barChart = (
    <ChartContainer
      config={barConfig}
      className={cn("aspect-auto w-full", longAxisLabels || manyCategories ? "h-[340px] sm:h-[360px]" : "h-[300px] sm:h-[320px]")}
    >
      <BarChart
        data={columnData}
        margin={{ left: 4, right: 8, top: 8, bottom: longAxisLabels || manyCategories ? 16 : 8 }}
      >
        <CartesianGrid vertical={false} strokeDasharray="3 3" className="stroke-border/50" />
        <XAxis
          dataKey="name"
          tickLine={false}
          axisLine={false}
          interval={0}
          height={longAxisLabels || manyCategories ? 72 : 40}
          angle={longAxisLabels || manyCategories ? -28 : 0}
          textAnchor={longAxisLabels || manyCategories ? "end" : "middle"}
          tick={{ fontSize: 11, fill: "hsl(var(--muted-foreground))" }}
          tickFormatter={(value) => truncateAxisLabel(String(value), manyCategories ? 12 : 18)}
        />
        <YAxis
          tickFormatter={(v) => `${v}%`}
          width={44}
          tick={{ fontSize: 11 }}
          axisLine={false}
          tickLine={false}
        />
        <ChartTooltip content={<AllocationBarTooltip />} cursor={{ fill: "hsl(var(--muted))", opacity: 0.35 }} />
        <ChartLegend content={<ChartLegendContent />} verticalAlign="top" />
        <Bar dataKey="ideal" fill="var(--color-ideal)" radius={[4, 4, 0, 0]} maxBarSize={36} name="ideal" />
        <Bar dataKey="actual" fill="var(--color-actual)" radius={[4, 4, 0, 0]} maxBarSize={36} name="actual" />
        {mode === "simulated" ? (
          <Bar
            dataKey="simulated"
            fill="var(--color-simulated)"
            radius={[4, 4, 0, 0]}
            maxBarSize={36}
            name="simulated"
          />
        ) : null}
      </BarChart>
    </ChartContainer>
  );

  const actualPie = (
    <DriftAllocationDonut
      data={actualDonutSource}
      config={donutConfig}
      resolveColor={(row, index) =>
        row.isVirtual ? "#f59e0b" : DRIFT_RULE_COLORS[index % DRIFT_RULE_COLORS.length]
      }
    />
  );

  if (resolvedLayout === "compact") {
    if (mode === "simulated") {
      return (
        <DriftSection title="Simulated mix" description="Portfolio split after what-if trades." icon={PieChartIcon}>
          <div className="p-4 sm:p-5">{actualPie}</div>
        </DriftSection>
      );
    }

    return (
      <div className="grid gap-4 lg:grid-cols-2">
        <DriftSection title="Ideal vs Actual" icon={BarChart3}>
          <div className="p-4 sm:p-5">{barChart}</div>
        </DriftSection>
        <DriftSection title="Actual mix" icon={PieChartIcon}>
          <div className="p-4 sm:p-5">{actualPie}</div>
        </DriftSection>
      </div>
    );
  }

  return (
    <div className="grid gap-4 lg:grid-cols-2">
      <DriftSection
        title="Actual allocation"
        description="Current portfolio split by segment."
        icon={PieChartIcon}
      >
        <div className="p-4 sm:p-5">{actualPie}</div>
      </DriftSection>
      <DriftSection
        title="Ideal (target) allocation"
        description="Target allocation defined in Drift Settings."
        icon={PieChartIcon}
      >
        <div className="p-4 sm:p-5">
          <DriftAllocationDonut
            data={idealDonutSource}
            config={idealDonutConfig}
            resolveColor={(row) => row.color ?? DRIFT_RULE_COLORS[0]}
          />
        </div>
      </DriftSection>
    </div>
  );
}
