// Central registry of trading algorithms. Combines built-in signal engines
// with user-defined "custom" algos generated on the fly. Enabled/disabled
// state and custom rule specs are persisted in localStorage so the browser
// strategy engine (use-client-signals) and the Pending Signals panel can
// share a single source of truth.

import { useCallback, useEffect, useState } from "react";

const LS_ENABLED = "algo_registry:enabled_v1";
const LS_CUSTOM = "algo_registry:custom_v1";

export type Condition = {
  indicator:
    | "rsi"
    | "ema_fast_gt_slow" // 1 if EMA20>EMA50 else 0
    | "macd_hist"
    | "price_vs_bb_upper" // 1 if close>=upper band else 0
    | "price_vs_bb_lower"; // 1 if close<=lower band else 0
  op: ">" | "<" | ">=" | "<=" | "==";
  value: number;
};

export type CustomAlgoSpec = {
  key: string; // e.g. "custom_pullback_v1"
  label: string;
  description?: string;
  timeframe: "15m" | "1h" | "any";
  confidence: number; // 0..1
  side_rules: {
    long: Condition[]; // AND
    short: Condition[]; // AND
  };
  created_at: string;
};

export const BUILTIN_ALGOS: { key: string; label: string }[] = [
  { key: "confluence", label: "Confluence" },
  { key: "ema_cross", label: "EMA Cross" },
  { key: "rsi_reversal", label: "RSI Reversal" },
  { key: "macd_momentum", label: "MACD Momentum" },
  { key: "bb_reversion", label: "BB Reversion" },
];

function readMap<T>(key: string, fallback: T): T {
  try {
    const raw = localStorage.getItem(key);
    if (!raw) return fallback;
    return JSON.parse(raw) as T;
  } catch {
    return fallback;
  }
}

function writeMap(key: string, value: unknown) {
  try {
    localStorage.setItem(key, JSON.stringify(value));
    window.dispatchEvent(new Event("algo-registry:change"));
  } catch {
    /* ignore */
  }
}

export function getEnabledMap(): Record<string, boolean> {
  const map = readMap<Record<string, boolean>>(LS_ENABLED, {});
  // Built-ins default to enabled when missing
  for (const a of BUILTIN_ALGOS) if (!(a.key in map)) map[a.key] = true;
  return map;
}

export function isAlgoEnabled(key: string): boolean {
  const map = getEnabledMap();
  return map[key] !== false;
}

export function setAlgoEnabled(key: string, enabled: boolean) {
  const map = getEnabledMap();
  map[key] = enabled;
  writeMap(LS_ENABLED, map);
}

export function getCustomAlgos(): CustomAlgoSpec[] {
  return readMap<CustomAlgoSpec[]>(LS_CUSTOM, []);
}

export function addCustomAlgo(spec: CustomAlgoSpec) {
  const list = getCustomAlgos().filter((a) => a.key !== spec.key);
  list.unshift(spec);
  writeMap(LS_CUSTOM, list);
  // enable by default
  setAlgoEnabled(spec.key, true);
}

export function removeCustomAlgo(key: string) {
  const list = getCustomAlgos().filter((a) => a.key !== key);
  writeMap(LS_CUSTOM, list);
  const en = getEnabledMap();
  delete en[key];
  writeMap(LS_ENABLED, en);
}

/** Reactive hook — re-renders on any registry mutation (this tab or others). */
export function useAlgoRegistry() {
  const [tick, setTick] = useState(0);
  useEffect(() => {
    const bump = () => setTick((t) => t + 1);
    window.addEventListener("algo-registry:change", bump);
    window.addEventListener("storage", bump);
    return () => {
      window.removeEventListener("algo-registry:change", bump);
      window.removeEventListener("storage", bump);
    };
  }, []);
  const enabled = getEnabledMap();
  const custom = getCustomAlgos();
  const all = [
    ...BUILTIN_ALGOS.map((a) => ({ ...a, custom: false as const })),
    ...custom.map((a) => ({ key: a.key, label: a.label, custom: true as const })),
  ];
  const toggle = useCallback((key: string, on: boolean) => setAlgoEnabled(key, on), []);
  const add = useCallback((spec: CustomAlgoSpec) => addCustomAlgo(spec), []);
  const remove = useCallback((key: string) => removeCustomAlgo(key), []);
  return { tick, enabled, custom, all, toggle, add, remove };
}
