"use client";

import * as React from "react";
import Link from "next/link";
import { Check, FlaskConical, Search, Plus, Save, Trash2, User, X } from "lucide-react";
import { toast } from "sonner";

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";

import { loadDriftPositions, loadDriftSettings, saveDriftSettings } from "../_lib/tenant-settings-api";
import type {
  DriftAllocationComparison,
  DriftDimensionKey,
  DriftIsinRule,
  DriftPositionsData,
  DriftRule,
  DriftSettingsData,
} from "../_lib/tenant-settings-server-api";
import { cn } from "@/lib/utils";
import { resolveAssetClassColor } from "@/lib/chart/asset-class-colors";
import { formatQuantity } from "@/lib/format/numbers";

const DIMENSIONS: Array<[DriftDimensionKey, string]> = [
  ["asset_class", "Asset Class"],
  ["asset_type", "Asset Type"],
  ["industry", "Industry"],
  ["sector", "Sector"],
  ["currency", "Currency"],
  ["country", "Country"],
];
const EMPTY_RULE = (): DriftRule => ({ dimensions: {}, target_percentage: 0 });
const EMPTY_ISIN = (): DriftIsinRule => ({ isin: "", target_percentage: 0 });

function colorForDriftLabel(label: string, index: number) {
  return resolveAssetClassColor(label, index);
}
const cleanLabel = (value: string) => value
  .replace(/<[^>]*>/g, " ")
  .replace(/&nbsp;/gi, " ")
  .replace(/&amp;/gi, "&")
  .replace(/\s+/g, " ")
  .trim();

function chartRulesForDimension(rules: DriftRule[], dimension: DriftDimensionKey) {
  const parents = new Set(
    rules
      .filter((rule) => Object.keys(rule.dimensions).length === 1 && rule.dimensions[dimension])
      .map((rule) => rule.dimensions[dimension]),
  );

  return rules.filter((rule) => {
    const value = rule.dimensions[dimension];
    if (!value) return false;
    return Object.keys(rule.dimensions).length === 1 || !parents.has(value);
  });
}

function Donut({
  slices,
  emptyLabel = "0%",
}: {
  slices: Array<{ value: number; color: string }>;
  emptyLabel?: string;
}) {
  const positive = slices.filter((slice) => Number.isFinite(slice.value) && slice.value > 0);
  const total = positive.reduce((sum, slice) => sum + slice.value, 0);
  const gradient = positive.reduce<{ cursor: number; stops: string[] }>(
    (result, slice) => {
      const end = result.cursor + Math.min(slice.value, Math.max(0, 100 - result.cursor));
      return {
        cursor: end,
        stops: [...result.stops, `${slice.color} ${result.cursor}% ${end}%`],
      };
    },
    { cursor: 0, stops: [] },
  );
  const stops = gradient.cursor < 100
    ? [...gradient.stops, `#f1f5f9 ${gradient.cursor}% 100%`]
    : gradient.stops;

  return (
    <div
      className="relative size-20 shrink-0 rounded-full"
      style={{ background: `conic-gradient(${stops.join(", ") || "#f1f5f9 0 100%"})` }}
    >
      <div className="absolute inset-[10px] grid place-items-center rounded-full bg-card">
        <span className={`font-semibold text-xs ${total > 100 ? "text-destructive" : ""}`}>
          {slices.length ? `${Number(total.toFixed(2))}%` : emptyLabel}
        </span>
      </div>
    </div>
  );
}

function TotalCards({
  rules,
  data,
  advanced = false,
}: {
  rules: DriftRule[];
  data: DriftSettingsData;
  advanced?: boolean;
}) {
  return (
    <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6">
      {DIMENSIONS.map(([key, label]) => {
        const dimensionRules = advanced
          ? rules.filter((rule) => rule.dimensions[key])
          : chartRulesForDimension(rules, key);
        const hasDimensionData = (data.dimensions[key] ?? []).length > 0;
        return (
          <div key={key} className="flex min-h-48 flex-col items-center rounded-xl border bg-card p-4 text-center">
            <Donut
              slices={dimensionRules.map((rule, index) => ({
                value: Number(rule.target_percentage || 0),
                color: colorForDriftLabel(cleanLabel(rule.dimensions[key] ?? ""), index),
              }))}
              emptyLabel={hasDimensionData ? "0%" : "N/A"}
            />
            <p className="mt-3 font-medium text-[11px] uppercase tracking-wide text-muted-foreground">{label}</p>
            <div className="mt-2 w-full space-y-1 text-left">
              {dimensionRules.slice(0, 3).map((rule, index) => (
                <div key={`${rule.dimensions[key]}-${index}`} className="flex min-w-0 items-center gap-1 text-[10px]">
                  <span
                    className="size-2 shrink-0 rounded-full"
                    style={{
                      backgroundColor: colorForDriftLabel(cleanLabel(rule.dimensions[key] ?? ""), index),
                    }}
                  />
                  <span className="truncate">{cleanLabel(rule.dimensions[key] ?? "")}</span>
                  <span className="ml-auto">{advanced ? (rule.operator === "gt" ? ">" : "<") : ""}{rule.target_percentage}%</span>
                </div>
              ))}
              {!dimensionRules.length && <p className="text-center text-muted-foreground text-xs">{hasDimensionData ? "No rules" : "No data"}</p>}
            </div>
          </div>
        );
      })}
    </div>
  );
}

function SearchableSelect({
  value,
  onChange,
  options,
  placeholder = "Select...",
  searchPlaceholder = "Search...",
  disabled = false,
  allowCustomValue = false,
}: {
  value: string;
  onChange: (value: string) => void;
  options: Array<{ value: string; label: string }>;
  placeholder?: string;
  searchPlaceholder?: string;
  disabled?: boolean;
  /** Let the typed text be committed as-is, for values not held in the portfolio yet. */
  allowCustomValue?: boolean;
}) {
  const [open, setOpen] = React.useState(false);
  const [search, setSearch] = React.useState("");

  const selectedOption = React.useMemo(
    () => options.find((opt) => opt.value === value),
    [options, value]
  );

  const filteredOptions = React.useMemo(() => {
    const q = search.trim().toLowerCase();
    if (!q) return options;
    return options.filter((opt) =>
      opt.label.toLowerCase().includes(q) || opt.value.toLowerCase().includes(q)
    );
  }, [options, search]);

  const customValue = search.trim();
  const canCreate =
    allowCustomValue &&
    customValue.length > 0 &&
    !options.some((opt) => opt.value.toLowerCase() === customValue.toLowerCase());

  const commitCustomValue = () => {
    if (!canCreate) return;
    onChange(customValue);
    setOpen(false);
    setSearch("");
  };

  return (
    <Popover open={open} onOpenChange={(next) => { setOpen(next); if (!next) setSearch(""); }}>
      <PopoverTrigger asChild>
        <Button
          variant="outline"
          role="combobox"
          aria-expanded={open}
          disabled={disabled}
          className="h-9 w-full justify-between bg-background px-3 font-normal text-sm hover:bg-accent/50 text-left"
        >
          <span className="truncate">{selectedOption?.label ?? placeholder}</span>
          <Search className="ml-2 size-3.5 shrink-0 opacity-40" />
        </Button>
      </PopoverTrigger>
      <PopoverContent className="w-[var(--radix-popover-trigger-width)] min-w-[260px] max-w-[420px] p-0 shadow-lg" align="start">
        <div className="p-2 border-b border-border/70 bg-muted/20">
          <div className="relative flex items-center">
            <Search className="absolute left-2.5 size-3.5 text-muted-foreground pointer-events-none" />
            <Input
              placeholder={searchPlaceholder}
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              onKeyDown={(e) => {
                if (e.key === "Enter" && canCreate) {
                  e.preventDefault();
                  commitCustomValue();
                }
              }}
              className="h-8 pl-8 pr-7 text-xs bg-background"
              autoFocus
            />
            {search ? (
              <button
                type="button"
                onClick={() => setSearch("")}
                className="absolute right-2 text-muted-foreground hover:text-foreground p-0.5 rounded-sm"
              >
                <X className="size-3" />
              </button>
            ) : null}
          </div>
        </div>
        <div className="max-h-60 overflow-y-auto p-1 space-y-0.5">
          {filteredOptions.map((opt) => {
            const isSelected = value === opt.value;
            return (
              <button
                key={opt.value}
                type="button"
                className={cn(
                  "flex w-full items-center justify-between rounded-md px-2.5 py-1.5 text-xs text-left transition-colors hover:bg-accent hover:text-accent-foreground",
                  isSelected && "bg-accent/70 font-medium text-foreground"
                )}
                onClick={() => {
                  onChange(opt.value);
                  setOpen(false);
                  setSearch("");
                }}
              >
                <span className="truncate pr-2" title={opt.label}>{opt.label}</span>
                {isSelected && <Check className="size-3.5 text-primary shrink-0 ml-auto" />}
              </button>
            );
          })}
          {canCreate && (
            <button
              type="button"
              className="flex w-full items-center gap-1.5 rounded-md px-2.5 py-1.5 text-xs text-left transition-colors hover:bg-accent hover:text-accent-foreground"
              onClick={commitCustomValue}
            >
              <Plus className="size-3.5 shrink-0 text-primary" />
              <span className="truncate">
                Use &ldquo;<span className="font-medium">{customValue}</span>&rdquo;
              </span>
            </button>
          )}
          {filteredOptions.length === 0 && !canCreate && (
            <div className="py-4 text-center text-xs text-muted-foreground">
              No matching options found
            </div>
          )}
        </div>
      </PopoverContent>
    </Popover>
  );
}

/**
 * Asset Type suggestions for the picked Asset Class, from the pairs the customer
 * actually holds. With no Asset Class picked we suggest the backend's `default` list,
 * which drops the instrument-level types (Structure, Accu/Decu) — those are one entry
 * per note rather than a reusable category. Falls back to the flat dimension list when
 * a backend without the map answers.
 */
function assetTypeSuggestions(
  data: DriftSettingsData,
  selectedAssetClass: string | undefined | null,
): string[] {
  const allAssetTypes = data.dimensions.asset_type ?? [];
  const assetTypeMap = data.assetTypeMap;
  if (!assetTypeMap) return allAssetTypes;

  if (!selectedAssetClass || selectedAssetClass === "__any__") {
    return assetTypeMap.default ?? allAssetTypes;
  }

  return assetTypeMap.byClass?.[selectedAssetClass] ?? [];
}

function RuleRow({
  rule,
  index,
  data,
  advanced,
  readOnly,
  onChange,
  onRemove,
}: {
  rule: DriftRule;
  index: number;
  data: DriftSettingsData;
  advanced?: boolean;
  readOnly?: boolean;
  onChange: (updatedRule: DriftRule) => void;
  onRemove: () => void;
}) {
  return (
    <div className="rounded-xl border bg-card p-4 space-y-3 shadow-xs">
      <div className="flex items-center justify-between">
        <span className="font-semibold text-sm text-foreground">
          {advanced ? "Advanced Rule " : "Rule "}{index + 1}
        </span>
        {!readOnly && (
          <Button
            variant="ghost"
            size="icon-sm"
            onClick={onRemove}
            title="Delete rule"
          >
            <Trash2 className="size-4 text-destructive hover:text-destructive/80" />
          </Button>
        )}
      </div>
      <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
        {DIMENSIONS.map(([key, label]) => {
          const currentValue = rule.dimensions[key];
          const availableOptions = key === "asset_type"
            ? assetTypeSuggestions(data, rule.dimensions.asset_class)
            : data.dimensions[key] ?? [];

          const options = currentValue && !availableOptions.includes(currentValue)
            ? [currentValue, ...availableOptions]
            : availableOptions;

          const dimensionOptions = [
            { value: "__any__", label: `Any ${label}` },
            ...options.map((val) => ({
              value: val,
              label: cleanLabel(val) || val,
            })),
          ];

          return (
            <SearchableSelect
              key={key}
              disabled={readOnly}
              value={currentValue || "__any__"}
              options={dimensionOptions}
              placeholder={`Any ${label}`}
              searchPlaceholder={key === "asset_type"
                ? "Search or type a new asset type…"
                : `Search ${label.toLowerCase()}…`}
              allowCustomValue={key === "asset_type"}
              onChange={(value) => {
                const dimensions = { ...rule.dimensions };
                if (value === "__any__") {
                  delete dimensions[key];
                } else {
                  dimensions[key] = value;
                }

                // Changing the class strands an asset type from the old class — but only
                // drop it if it came from the portfolio; a hand-typed one is deliberate.
                if (key === "asset_class" && dimensions.asset_type) {
                  const heldTypes = data.dimensions.asset_type ?? [];
                  const validTypes = assetTypeSuggestions(
                    data,
                    value === "__any__" ? undefined : value,
                  );
                  if (
                    heldTypes.includes(dimensions.asset_type) &&
                    !validTypes.includes(dimensions.asset_type)
                  ) {
                    delete dimensions.asset_type;
                  }
                }

                onChange({ ...rule, dimensions });
              }}
            />
          );
        })}
        {advanced && (
          <Select
            disabled={readOnly}
            value={rule.operator ?? "lt"}
            onValueChange={(operator) =>
              onChange({ ...rule, operator: operator as "lt" | "gt" })
            }
          >
            <SelectTrigger className="w-full h-9 bg-background justify-between">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="lt">Below target (&lt;)</SelectItem>
              <SelectItem value="gt">Above target (&gt;)</SelectItem>
            </SelectContent>
          </Select>
        )}
        <div className="relative w-full">
          <Input
            disabled={readOnly}
            type="number"
            min="0.01"
            max="100"
            step="0.01"
            className="h-9 w-full bg-background pr-7"
            value={rule.target_percentage || ""}
            onChange={(event) =>
              onChange({
                ...rule,
                target_percentage: Number(event.target.value),
              })
            }
            placeholder="Target %"
          />
          <span className="pointer-events-none absolute right-2.5 top-1/2 -translate-y-1/2 text-xs text-muted-foreground">%</span>
        </div>
      </div>
    </div>
  );
}

function RuleEditor({
  title,
  rules,
  data,
  advanced,
  readOnly = false,
  onChange,
}: {
  title: string;
  rules: DriftRule[];
  data: DriftSettingsData;
  advanced?: boolean;
  readOnly?: boolean;
  onChange: (rules: DriftRule[]) => void;
}) {
  return (
    <section className="space-y-3 rounded-xl border bg-card p-4">
      <div className="flex items-center justify-between">
        <div>
          <h3 className="font-semibold text-base">{title}</h3>
          <p className="text-muted-foreground text-xs">
            Each unique dimension combination defines a portfolio target.
          </p>
        </div>
        {!readOnly && (
          <Button
            variant="outline"
            size="sm"
            className="gap-2"
            onClick={() =>
              onChange([
                ...rules,
                { ...EMPTY_RULE(), ...(advanced ? { operator: "lt" as const } : {}) },
              ])
            }
          >
            <Plus className="size-4" />
            Add rule
          </Button>
        )}
      </div>
      {!rules.length && (
        <p className="rounded-lg bg-muted/50 p-5 text-center text-muted-foreground text-sm">
          No rules defined.
        </p>
      )}
      {rules.map((rule, index) => (
        <RuleRow
          key={index}
          rule={rule}
          index={index}
          data={data}
          advanced={advanced}
          readOnly={readOnly}
          onChange={(updatedRule) =>
            onChange(rules.map((item, i) => (i === index ? updatedRule : item)))
          }
          onRemove={() =>
            onChange(rules.filter((_, i) => i !== index))
          }
        />
      ))}
    </section>
  );
}

function IsinRow({
  rule,
  index,
  data,
  advanced,
  tenant,
  readOnly,
  customerId,
  openIsin,
  positions,
  positionsLoading,
  togglePositions,
  onChange,
  onRemove,
}: {
  rule: DriftIsinRule;
  index: number;
  data: DriftSettingsData;
  advanced?: boolean;
  tenant: string;
  readOnly?: boolean;
  customerId?: number | null;
  openIsin: string;
  positions: DriftPositionsData["positions"] | null;
  positionsLoading: boolean;
  togglePositions: (isin: string) => Promise<void>;
  onChange: (updatedRule: DriftIsinRule) => void;
  onRemove: () => void;
}) {
  const rawIsins = React.useMemo(
    () => data.isinList.map((item) => (typeof item === "string" ? { code: item, name: item } : item)),
    [data.isinList]
  );
  const isins = React.useMemo(() => {
    if (rule.isin && !rawIsins.some((item) => item.code === rule.isin)) {
      return [{ code: rule.isin, name: rule.isin }, ...rawIsins];
    }
    return rawIsins;
  }, [rawIsins, rule.isin]);

  return (
    <div className="rounded-xl border bg-card p-4 space-y-3 shadow-xs">
      <div className="flex flex-wrap items-center gap-3">
        <div className="flex-1 min-w-[200px]">
          <SearchableSelect
            disabled={readOnly}
            value={rule.isin || "__none__"}
            options={[
              { value: "__none__", label: "Select ISIN" },
              ...isins.map((item) => ({
                value: item.code,
                label: item.name || item.code,
              })),
            ]}
            placeholder="Select ISIN"
            searchPlaceholder="Search ISIN or security name…"
            onChange={(isin) =>
              onChange({ ...rule, isin: isin === "__none__" ? "" : isin })
            }
          />
        </div>
        {advanced && (
          <div className="w-[160px]">
            <Select
              disabled={readOnly}
              value={rule.operator ?? "lt"}
              onValueChange={(operator) =>
                onChange({ ...rule, operator: operator as "lt" | "gt" })
              }
            >
              <SelectTrigger className="w-full h-9 bg-background justify-between">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="lt">Below target (&lt;)</SelectItem>
                <SelectItem value="gt">Above target (&gt;)</SelectItem>
              </SelectContent>
            </Select>
          </div>
        )}
        <div className="relative w-[140px]">
          <Input
            disabled={readOnly}
            type="number"
            min="0.01"
            max="100"
            step="0.01"
            className="h-9 w-full bg-background pr-7"
            value={rule.target_percentage || ""}
            onChange={(event) =>
              onChange({
                ...rule,
                target_percentage: Number(event.target.value),
              })
            }
            placeholder="Target %"
          />
          <span className="pointer-events-none absolute right-2.5 top-1/2 -translate-y-1/2 text-xs text-muted-foreground">%</span>
        </div>
        <Button
          variant="outline"
          size="sm"
          className="h-9"
          disabled={!rule.isin}
          onClick={() => void togglePositions(rule.isin)}
        >
          {openIsin === rule.isin ? "Hide" : "Positions"}
        </Button>
        {!readOnly && (
          <Button
            variant="ghost"
            size="icon-sm"
            onClick={onRemove}
            title="Delete rule"
          >
            <Trash2 className="size-4 text-destructive hover:text-destructive/80" />
          </Button>
        )}
      </div>
      {openIsin === rule.isin && (
        <div className="mt-3 overflow-x-auto rounded-lg bg-muted/40 p-3">
          {positionsLoading ? (
            <p className="text-muted-foreground text-sm">Loading positions…</p>
          ) : positions?.rows.length ? (
            <>
              <p className="mb-2 font-medium text-sm">
                Total {formatQuantity(positions.total)} {positions.currency}
              </p>
              <table className="w-full text-left text-xs">
                <thead>
                  <tr>
                    {["Name", "ISIN", "Bank", "Qty", "Price", "Value"].map((heading) => (
                      <th key={heading} className="border-b p-2 font-medium">
                        {heading}
                      </th>
                    ))}
                  </tr>
                </thead>
                <tbody>
                  {positions.rows.map((position, positionIndex) => (
                    <tr key={`${position.ticker}-${position.bank_name}-${positionIndex}`}>
                      <td className="p-2">{position.name}</td>
                      <td className="p-2 font-mono">{position.isin || position.ticker}</td>
                      <td className="p-2">{position.bank_name}</td>
                      <td className="p-2">{position.qty}</td>
                      <td className="p-2">{position.price}</td>
                      <td className="p-2">{formatQuantity(position.value)}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </>
          ) : (
            <p className="text-muted-foreground text-sm">No positions found.</p>
          )}
        </div>
      )}
    </div>
  );
}

function IsinEditor({
  title,
  rules,
  data,
  advanced,
  tenant,
  readOnly = false,
  customerId,
  onChange,
}: {
  title: string;
  rules: DriftIsinRule[];
  data: DriftSettingsData;
  advanced?: boolean;
  tenant: string;
  readOnly?: boolean;
  customerId?: number | null;
  onChange: (rules: DriftIsinRule[]) => void;
}) {
  const [openIsin, setOpenIsin] = React.useState("");
  const [positions, setPositions] = React.useState<DriftPositionsData["positions"] | null>(null);
  const [positionsLoading, setPositionsLoading] = React.useState(false);

  async function togglePositions(isin: string) {
    if (openIsin === isin) {
      setOpenIsin("");
      setPositions(null);
      return;
    }
    setOpenIsin(isin);
    setPositions(null);
    setPositionsLoading(true);
    try {
      const result = await loadDriftPositions(tenant, isin, customerId);
      setPositions(result.positions);
    } catch (loadError) {
      toast.error(loadError instanceof Error ? loadError.message : "Positions could not be loaded.");
    } finally {
      setPositionsLoading(false);
    }
  }

  return (
    <section className="space-y-3 rounded-xl border bg-card p-4">
      <div className="flex items-center justify-between">
        <div>
          <h3 className="font-semibold text-base">{title}</h3>
          <p className="text-muted-foreground text-xs">
            Allocate directly to a security identifier.
          </p>
        </div>
        {!readOnly && (
          <Button
            variant="outline"
            size="sm"
            className="gap-2"
            onClick={() =>
              onChange([
                ...rules,
                { ...EMPTY_ISIN(), ...(advanced ? { operator: "lt" as const } : {}) },
              ])
            }
          >
            <Plus className="size-4" />
            Add ISIN
          </Button>
        )}
      </div>
      {rules.map((rule, index) => (
        <IsinRow
          key={index}
          rule={rule}
          index={index}
          data={data}
          advanced={advanced}
          tenant={tenant}
          readOnly={readOnly}
          customerId={customerId}
          openIsin={openIsin}
          positions={positions}
          positionsLoading={positionsLoading}
          togglePositions={togglePositions}
          onChange={(updatedRule) =>
            onChange(rules.map((item, i) => (i === index ? updatedRule : item)))
          }
          onRemove={() =>
            onChange(rules.filter((_, i) => i !== index))
          }
        />
      ))}
      {!rules.length && (
        <p className="rounded-lg bg-muted/50 p-5 text-center text-muted-foreground text-sm">
          No ISIN rules defined.
        </p>
      )}
    </section>
  );
}

function apiRules(rules: DriftRule[]) {
  return rules.map((rule) => ({ ...rule.dimensions, target_percentage: rule.target_percentage, ...(rule.operator ? { operator: rule.operator } : {}) }));
}

function IsinAllocationSummary({
  rules,
  data,
}: {
  rules: DriftIsinRule[];
  data: DriftSettingsData;
}) {
  const names = new Map(
    data.isinList.map((item) => typeof item === "string" ? [item, item] : [item.code, item.name]),
  );
  return (
    <section className="space-y-3 border-t pt-5">
      <div className="flex items-baseline gap-2">
        <h3 className="font-semibold">Allocate by ISIN</h3>
        <span className="text-muted-foreground text-xs">{rules.length} rules</span>
      </div>
      <div className="flex min-h-36 items-center gap-6 rounded-xl border bg-card p-5">
        <Donut
          slices={rules.map((rule, index) => ({
            value: Number(rule.target_percentage),
            color: colorForDriftLabel(rule.isin || names.get(rule.isin) || "", index),
          }))}
        />
        <div className="grid flex-1 gap-2 sm:grid-cols-2">
          {rules.map((rule, index) => (
            <div key={`${rule.isin}-${index}`} className="flex items-center gap-2 text-sm">
              <span
                className="size-2.5 shrink-0 rounded-full"
                style={{ backgroundColor: colorForDriftLabel(rule.isin || "", index) }}
              />
              <span className="truncate">{names.get(rule.isin) ?? rule.isin}</span>
              <span className="ml-auto font-medium">{rule.target_percentage}%</span>
            </div>
          ))}
          {!rules.length && <p className="text-muted-foreground text-sm">No ISIN rules</p>}
        </div>
      </div>
    </section>
  );
}

function RulesOverview({ rules }: { rules: DriftRule[] }) {
  if (!rules.length) {
    return <p className="py-12 text-center text-muted-foreground">No target allocations defined.</p>;
  }
  return (
    <div className="space-y-2">
      {rules.map((rule, index) => (
        <div key={index} className="flex flex-wrap items-center gap-2 rounded-xl border bg-card p-4">
          <span
            className="size-3 rounded-full"
            style={{
              backgroundColor: colorForDriftLabel(
                cleanLabel(Object.values(rule.dimensions).filter(Boolean).join(" / ")),
                index,
              ),
            }}
          />
          <span className="font-medium text-sm">Rule #{index + 1}</span>
          <span className="mr-auto text-muted-foreground text-sm">
            {Object.entries(rule.dimensions)
              .map(([key, value]) => `${DIMENSIONS.find(([dimension]) => dimension === key)?.[1] ?? key}: ${cleanLabel(value)}`)
              .join(" · ")}
          </span>
          <span className="font-semibold">{rule.target_percentage}%</span>
        </div>
      ))}
    </div>
  );
}

function AllocationRows({
  title,
  rows,
  currency,
}: {
  title: string;
  rows: DriftAllocationComparison[];
  currency: string;
}) {
  if (!rows.length) return null;
  return (
    <section className="overflow-hidden rounded-xl border bg-card">
      <div className="border-b px-4 py-3"><h3 className="font-semibold">{title}</h3></div>
      <div className="overflow-x-auto">
        <table className="w-full min-w-[780px] text-left text-sm">
          <thead className="bg-muted/50 text-muted-foreground">
            <tr>
              {["Target", "Ideal", "Actual", "Drift", "Actual Value", "Target Value", "Action"].map((heading) => (
                <th key={heading} className="px-4 py-3 font-medium">{heading}</th>
              ))}
            </tr>
          </thead>
          <tbody className="divide-y">
            {rows.map((row, index) => (
              <tr key={`${row.rule_label}-${index}`}>
                <td className="max-w-72 px-4 py-3 font-medium">{row.rule_label}</td>
                <td className="px-4 py-3">{row.ideal_pct}%</td>
                <td className="px-4 py-3">{row.actual_pct}%</td>
                <td className={`px-4 py-3 font-medium ${row.drift > 0 ? "text-amber-600" : row.drift < 0 ? "text-blue-600" : "text-emerald-600"}`}>{row.drift > 0 ? "+" : ""}{row.drift}%</td>
                <td className="px-4 py-3">{formatQuantity(Number(row.actual_value))} {currency}</td>
                <td className="px-4 py-3">{formatQuantity(Number(row.target_value))} {currency}</td>
                <td className="px-4 py-3">
                  <span className={`rounded-full px-2 py-1 text-xs ${row.reallocate_action === "add" ? "bg-blue-100 text-blue-700" : row.reallocate_action === "reduce" ? "bg-amber-100 text-amber-700" : "bg-emerald-100 text-emerald-700"}`}>
                    {row.reallocate_action === "add" ? "Add" : row.reallocate_action === "reduce" ? "Reduce" : "On target"}
                  </span>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </section>
  );
}

function ActualVsIdeal({ data }: { data: DriftSettingsData }) {
  if (!data.selectedCustomerId) {
    return <p className="py-4 text-muted-foreground text-sm">Select a customer above to see their Actual vs Ideal Allocation report.</p>;
  }
  const report = data.driftReportData;
  if (report?.error) {
    return <p className="rounded-xl border border-destructive/30 bg-destructive/5 p-4 text-destructive text-sm">Report could not be loaded: {report.error}</p>;
  }
  const comparison = report?.comparison ?? [];
  const isinComparison = report?.isinComparison ?? [];
  if (!comparison.length && !isinComparison.length) {
    return <p className="py-4 text-muted-foreground text-sm">No target rules or portfolio data. Define targets and save to generate the report.</p>;
  }

  return (
    <div className="space-y-4">
      <div className="rounded-xl border bg-card p-4">
        <p className="text-muted-foreground text-xs uppercase tracking-wide">Total portfolio value</p>
        <p className="mt-1 font-semibold text-xl">{formatQuantity(Number(report?.totalPortfolioValue ?? 0))} {report?.reportingCode ?? ""}</p>
      </div>
      <AllocationRows title="Target allocation" rows={comparison} currency={report?.reportingCode ?? ""} />
      <AllocationRows title="ISIN allocation" rows={isinComparison} currency={report?.reportingCode ?? ""} />
    </div>
  );
}

export function SettingsPanelDrift({ tenant }: { tenant: string }) {
  const [data, setData] = React.useState<DriftSettingsData | null>(null);
  const [rules, setRules] = React.useState<DriftRule[]>([]);
  const [isinRules, setIsinRules] = React.useState<DriftIsinRule[]>([]);
  const [advanced, setAdvanced] = React.useState<DriftRule[]>([]);
  const [advancedIsin, setAdvancedIsin] = React.useState<DriftIsinRule[]>([]);
  const [activeTab, setActiveTab] = React.useState("charts");
  const [customerSearch, setCustomerSearch] = React.useState("");
  const [customerDropdownOpen, setCustomerDropdownOpen] = React.useState(false);
  const [loading, setLoading] = React.useState(true);
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);

  const applyData = React.useCallback((result: DriftSettingsData) => {
    setData(result);
    setRules(result.rules ?? []);
    setIsinRules(result.isinRules ?? []);
    setAdvanced(result.advancedRules ?? []);
    setAdvancedIsin(result.advancedIsinRules ?? []);
    if (result.selectedCustomerId) {
      setCustomerSearch(result.customerList[String(result.selectedCustomerId)] ?? "");
    }
  }, []);

  React.useEffect(() => {
    let cancelled = false;
    void loadDriftSettings(tenant).then((result) => {
      if (cancelled) return;
      applyData(result);
    }).catch((loadError) => { if (!cancelled) setError(loadError instanceof Error ? loadError.message : "Drift Settings could not be loaded."); })
      .finally(() => { if (!cancelled) setLoading(false); });
    return () => { cancelled = true; };
  }, [applyData, tenant]);

  async function selectCustomer(customerId: number | null) {
    setLoading(true);
    setError(null);
    try {
      const result = await loadDriftSettings(tenant, customerId);
      applyData(result);
      if (!customerId) setCustomerSearch("");
      setCustomerDropdownOpen(false);
    } catch (loadError) {
      setError(loadError instanceof Error ? loadError.message : "Customer allocation could not be loaded.");
    } finally {
      setLoading(false);
    }
  }

  async function saveStandard() {
    setBusy(true);
    try {
      const result = await saveDriftSettings(tenant, { operation: "standard", rules: apiRules(rules), isinRules });
      applyData(result);
      toast.success("Drift Settings saved");
    } catch (saveError) { toast.error(saveError instanceof Error ? saveError.message : "Drift Settings could not be saved."); }
    finally { setBusy(false); }
  }

  async function saveAdvanced() {
    setBusy(true);
    try {
      const result = await saveDriftSettings(tenant, {
        operation: "advanced",
        rules: apiRules(advanced),
        isinRules: advancedIsin,
      });
      applyData(result);
      toast.success("Advanced Drift Settings saved");
    } catch (saveError) { toast.error(saveError instanceof Error ? saveError.message : "Advanced settings could not be saved."); }
    finally { setBusy(false); }
  }

  if (loading) return <p className="py-12 text-center text-muted-foreground text-sm">Loading Drift Settings…</p>;
  if (error || !data) return <p className="rounded-lg border border-destructive/30 bg-destructive/5 p-4 text-destructive text-sm">{error}</p>;

  const customerOptions = Object.entries(data.customerList ?? {});
  const filteredCustomers = customerOptions.filter(([, name]) =>
    name.toLowerCase().includes(customerSearch.trim().toLowerCase()),
  );
  const showStandardRules = activeTab === "charts" || activeTab === "overview";

  return (
    <div className="space-y-5">
      <div className="flex flex-wrap items-start justify-between gap-3">
        <div>
          <h2 className="font-semibold text-xl">Target Allocation Rules</h2>
          <p className="text-muted-foreground text-sm">
            {data.isReadOnly
              ? "Portfolio target allocation summary"
              : "Define your portfolio targets — each dimension total must not exceed 100%"}
          </p>
        </div>
        {!data.isReadOnly ? (
          <Button type="button" variant="outline" size="sm" asChild className="gap-2">
            <Link href={`/customer/${tenant}/reports/portfolio-simulator`}>
              <FlaskConical className="size-3.5" />
              What-If Simulator
            </Link>
          </Button>
        ) : null}
      </div>

      {data.isReadOnly && (
        <div className="relative rounded-xl border bg-card p-3">
          <div className="flex items-center gap-3">
            <label className="flex shrink-0 items-center gap-1 font-medium text-sm"><User className="size-4 text-primary" />Customer:</label>
            <div className="relative flex-1">
              <Search className="pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground" />
              <Input
                value={customerSearch}
                onFocus={() => setCustomerDropdownOpen(true)}
                onBlur={() => window.setTimeout(() => setCustomerDropdownOpen(false), 150)}
                onChange={(event) => {
                  setCustomerSearch(event.target.value);
                  setCustomerDropdownOpen(true);
                }}
                placeholder="Search customers..."
                className="pr-9 pl-9"
              />
              {data.selectedCustomerId && (
                <button
                  type="button"
                  className="absolute top-1/2 right-3 -translate-y-1/2 text-muted-foreground hover:text-foreground"
                  onClick={() => void selectCustomer(null)}
                  aria-label="Clear customer"
                >
                  <X className="size-4" />
                </button>
              )}
              {customerDropdownOpen && (
                <div className="absolute z-30 mt-1 max-h-64 w-full overflow-y-auto rounded-lg border bg-popover p-1 shadow-lg">
                  {filteredCustomers.map(([id, name]) => (
                    <button
                      key={id}
                      type="button"
                      className="block w-full rounded-md px-3 py-2 text-left text-sm hover:bg-accent"
                      onMouseDown={(event) => event.preventDefault()}
                      onClick={() => void selectCustomer(Number(id))}
                    >
                      {name}
                    </button>
                  ))}
                  {!filteredCustomers.length && <p className="p-3 text-center text-muted-foreground text-sm">No customers found.</p>}
                </div>
              )}
            </div>
          </div>
        </div>
      )}

      <Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-4">
        <TabsList className={`grid h-10 w-full ${data.isReadOnly ? "grid-cols-4" : "grid-cols-3"}`}>
          <TabsTrigger value="charts">Charts</TabsTrigger>
          <TabsTrigger value="overview">Overview</TabsTrigger>
          <TabsTrigger value="advanced">Advanced</TabsTrigger>
          {data.isReadOnly && <TabsTrigger value="report">Actual vs Ideal</TabsTrigger>}
        </TabsList>

        <TabsContent value="charts" className="space-y-5">
          <TotalCards rules={rules} data={data} />
          <IsinAllocationSummary rules={isinRules} data={data} />
        </TabsContent>
        <TabsContent value="overview" className="space-y-5">
          <RulesOverview rules={rules} />
          <IsinAllocationSummary rules={isinRules} data={data} />
        </TabsContent>
        <TabsContent value="advanced" className="space-y-5">
          <TotalCards rules={advanced} data={data} advanced />
          <RuleEditor title="Advanced Rules" rules={advanced} data={data} advanced readOnly={data.isReadOnly} onChange={setAdvanced} />
          <IsinEditor title="ISIN Advanced Rules" rules={advancedIsin} data={data} tenant={tenant} customerId={data.selectedCustomerId} advanced readOnly={data.isReadOnly} onChange={setAdvancedIsin} />
          {!data.isReadOnly && (
            <div className="flex justify-end">
              <Button className="gap-2" disabled={busy} onClick={() => void saveAdvanced()}>
                <Save className="size-4" />{busy ? "Saving…" : "Save Advanced Rules"}
              </Button>
            </div>
          )}
        </TabsContent>
        {data.isReadOnly && <TabsContent value="report"><ActualVsIdeal data={data} /></TabsContent>}
      </Tabs>

      {showStandardRules && !data.isReadOnly && (
        <div className="space-y-4">
          <RuleEditor title="Rules" rules={rules} data={data} onChange={setRules} />
          <IsinEditor title="Allocate by ISIN" rules={isinRules} data={data} tenant={tenant} onChange={setIsinRules} />
          <div className="flex justify-end">
            <Button className="gap-2" disabled={busy} onClick={() => void saveStandard()}>
              <Save className="size-4" />{busy ? "Saving…" : "Save Settings"}
            </Button>
          </div>
        </div>
      )}
    </div>
  );
}
