// Lightweight user preferences persisted to localStorage. Kept separate
// from the app-wide branding settings so per-user UI knobs (like the
// Signals history page size) don't require a backend round-trip.
import { useEffect, useState } from "react";

const SIGNALS_PAGE_SIZE_KEY = "delta-terminal:signals-page-size";
const ALLOWED_PAGE_SIZES = [10, 20, 50, 100] as const;
export type SignalsPageSize = (typeof ALLOWED_PAGE_SIZES)[number];
export const SIGNALS_PAGE_SIZE_OPTIONS: readonly SignalsPageSize[] = ALLOWED_PAGE_SIZES;
export const DEFAULT_SIGNALS_PAGE_SIZE: SignalsPageSize = 10;

function readPageSize(): SignalsPageSize {
  if (typeof window === "undefined") return DEFAULT_SIGNALS_PAGE_SIZE;
  const raw = Number(window.localStorage.getItem(SIGNALS_PAGE_SIZE_KEY));
  return (ALLOWED_PAGE_SIZES as readonly number[]).includes(raw)
    ? (raw as SignalsPageSize)
    : DEFAULT_SIGNALS_PAGE_SIZE;
}

export function getSignalsPageSize(): SignalsPageSize {
  return readPageSize();
}

/** Reactive hook — updates when other tabs (or Settings) change the value. */
export function useSignalsPageSize(): [SignalsPageSize, (n: SignalsPageSize) => void] {
  const [n, setN] = useState<SignalsPageSize>(() => readPageSize());
  useEffect(() => {
    const onStorage = (e: StorageEvent) => {
      if (e.key === SIGNALS_PAGE_SIZE_KEY) setN(readPageSize());
    };
    const onCustom = () => setN(readPageSize());
    window.addEventListener("storage", onStorage);
    window.addEventListener("delta-terminal:prefs-changed", onCustom);
    return () => {
      window.removeEventListener("storage", onStorage);
      window.removeEventListener("delta-terminal:prefs-changed", onCustom);
    };
  }, []);
  const set = (next: SignalsPageSize) => {
    window.localStorage.setItem(SIGNALS_PAGE_SIZE_KEY, String(next));
    window.dispatchEvent(new Event("delta-terminal:prefs-changed"));
    setN(next);
  };
  return [n, set];
}

// ---------------------------------------------------------------------------
// Trade limits — cap concurrent open positions and/or new trades per day.
// Empty string / undefined means "no restriction". Values are stored as
// strings so an empty input round-trips cleanly.

const LIMIT_ACTIVE_KEY = "delta-terminal:limit-active";
const LIMIT_DAILY_KEY = "delta-terminal:limit-daily";
const TRADES_LOG_KEY = "delta-terminal:trades-initiated";

export interface TradeLimits {
  maxActive: number | null;
  maxPerDay: number | null;
}

function parseLimit(raw: string | null): number | null {
  if (raw == null) return null;
  const s = raw.trim();
  if (!s) return null;
  const n = Number(s);
  return Number.isFinite(n) && n > 0 ? Math.floor(n) : null;
}

function readLimits(): TradeLimits {
  if (typeof window === "undefined") return { maxActive: null, maxPerDay: null };
  return {
    maxActive: parseLimit(window.localStorage.getItem(LIMIT_ACTIVE_KEY)),
    maxPerDay: parseLimit(window.localStorage.getItem(LIMIT_DAILY_KEY)),
  };
}

export function getTradeLimits(): TradeLimits {
  return readLimits();
}

/** Reactive hook — accepts raw strings so an empty input means "unlimited". */
export function useTradeLimits(): {
  activeRaw: string;
  dailyRaw: string;
  limits: TradeLimits;
  setActive: (v: string) => void;
  setDaily: (v: string) => void;
} {
  const [activeRaw, setActiveRaw] = useState<string>(() =>
    typeof window === "undefined" ? "" : window.localStorage.getItem(LIMIT_ACTIVE_KEY) ?? "",
  );
  const [dailyRaw, setDailyRaw] = useState<string>(() =>
    typeof window === "undefined" ? "" : window.localStorage.getItem(LIMIT_DAILY_KEY) ?? "",
  );
  useEffect(() => {
    const sync = () => {
      setActiveRaw(window.localStorage.getItem(LIMIT_ACTIVE_KEY) ?? "");
      setDailyRaw(window.localStorage.getItem(LIMIT_DAILY_KEY) ?? "");
    };
    window.addEventListener("storage", sync);
    window.addEventListener("delta-terminal:prefs-changed", sync);
    return () => {
      window.removeEventListener("storage", sync);
      window.removeEventListener("delta-terminal:prefs-changed", sync);
    };
  }, []);
  const setActive = (v: string) => {
    window.localStorage.setItem(LIMIT_ACTIVE_KEY, v);
    window.dispatchEvent(new Event("delta-terminal:prefs-changed"));
    setActiveRaw(v);
  };
  const setDaily = (v: string) => {
    window.localStorage.setItem(LIMIT_DAILY_KEY, v);
    window.dispatchEvent(new Event("delta-terminal:prefs-changed"));
    setDailyRaw(v);
  };
  return {
    activeRaw,
    dailyRaw,
    limits: {
      maxActive: parseLimit(activeRaw),
      maxPerDay: parseLimit(dailyRaw),
    },
    setActive,
    setDaily,
  };
}

/** Return timestamps (ms) of trades initiated today. */
function readTradeLog(): number[] {
  if (typeof window === "undefined") return [];
  try {
    const arr = JSON.parse(window.localStorage.getItem(TRADES_LOG_KEY) ?? "[]");
    if (!Array.isArray(arr)) return [];
    const start = new Date();
    start.setHours(0, 0, 0, 0);
    return arr.filter((n: unknown) => typeof n === "number" && n >= start.getTime());
  } catch {
    return [];
  }
}

export function countTradesToday(): number {
  return readTradeLog().length;
}

export function recordTradeInitiated(): void {
  if (typeof window === "undefined") return;
  const log = [...readTradeLog(), Date.now()];
  window.localStorage.setItem(TRADES_LOG_KEY, JSON.stringify(log));
}

/**
 * Check trade limits given the current live active-trade count.
 * Returns null when allowed, or a human-readable reason string.
 */
export function checkTradeLimits(activeCount: number): string | null {
  const { maxActive, maxPerDay } = readLimits();
  if (maxActive != null && activeCount >= maxActive) {
    return `Max concurrent trades reached (${activeCount}/${maxActive}). Close a position or raise the limit in Settings.`;
  }
  if (maxPerDay != null) {
    const today = countTradesToday();
    if (today >= maxPerDay) {
      return `Daily trade cap reached (${today}/${maxPerDay}). Increase the limit in Settings to open more.`;
    }
  }
  return null;
}

// ---------------------------------------------------------------------------
// Allowed coins — if non-empty, only these symbols may generate signals or
// be approved for trading. An empty list means "no restriction" (all coins).

const ALLOWED_COINS_KEY = "delta-terminal:allowed-coins";

function readAllowedCoins(): string[] {
  if (typeof window === "undefined") return [];
  try {
    const raw = window.localStorage.getItem(ALLOWED_COINS_KEY);
    if (!raw) return [];
    const arr = JSON.parse(raw);
    if (!Array.isArray(arr)) return [];
    return arr
      .map((s) => String(s ?? "").trim().toUpperCase())
      .filter((s) => s.length > 0);
  } catch {
    return [];
  }
}

export function getAllowedCoins(): string[] {
  return readAllowedCoins();
}

/** null / empty list means "all coins allowed". */
export function isCoinAllowed(symbol: string): boolean {
  const list = readAllowedCoins();
  if (list.length === 0) return true;
  return list.includes(String(symbol ?? "").toUpperCase());
}

export function useAllowedCoins(): {
  coins: string[];
  add: (symbol: string) => void;
  remove: (symbol: string) => void;
  clear: () => void;
} {
  const [coins, setCoins] = useState<string[]>(() => readAllowedCoins());
  useEffect(() => {
    const sync = () => setCoins(readAllowedCoins());
    window.addEventListener("storage", sync);
    window.addEventListener("delta-terminal:prefs-changed", sync);
    return () => {
      window.removeEventListener("storage", sync);
      window.removeEventListener("delta-terminal:prefs-changed", sync);
    };
  }, []);
  const write = (next: string[]) => {
    const uniq = Array.from(new Set(next.map((s) => s.trim().toUpperCase()).filter(Boolean)));
    window.localStorage.setItem(ALLOWED_COINS_KEY, JSON.stringify(uniq));
    window.dispatchEvent(new Event("delta-terminal:prefs-changed"));
    setCoins(uniq);
  };
  return {
    coins,
    add: (s) => write([...coins, s]),
    remove: (s) => write(coins.filter((x) => x !== s.trim().toUpperCase())),
    clear: () => write([]),
  };
}

// ---------------------------------------------------------------------------
// Risk profile — default sizing type/value, leverage, and per-trade risk cap.
// Persisted so pending-signal cards and manual trade panels can pre-fill from
// the user's Settings choices instead of hard-coded defaults.

const RISK_PROFILE_KEY = "delta-terminal:risk-profile";

export interface RiskProfile {
  sizingType: "FIXED_AMOUNT" | "PERCENTAGE";
  sizingValue: number;
  leverage: number;
  maxRiskPct: number;
}

export const DEFAULT_RISK_PROFILE: RiskProfile = {
  sizingType: "PERCENTAGE",
  sizingValue: 2,
  leverage: 10,
  maxRiskPct: 2,
};

function readRiskProfile(): RiskProfile {
  if (typeof window === "undefined") return DEFAULT_RISK_PROFILE;
  try {
    const raw = window.localStorage.getItem(RISK_PROFILE_KEY);
    if (!raw) return DEFAULT_RISK_PROFILE;
    const p = JSON.parse(raw) as Partial<RiskProfile>;
    return {
      sizingType: p.sizingType === "FIXED_AMOUNT" ? "FIXED_AMOUNT" : "PERCENTAGE",
      sizingValue: Number.isFinite(p.sizingValue) && (p.sizingValue as number) > 0 ? (p.sizingValue as number) : DEFAULT_RISK_PROFILE.sizingValue,
      leverage: Number.isFinite(p.leverage) && (p.leverage as number) >= 1 ? (p.leverage as number) : DEFAULT_RISK_PROFILE.leverage,
      maxRiskPct: Number.isFinite(p.maxRiskPct) && (p.maxRiskPct as number) > 0 ? (p.maxRiskPct as number) : DEFAULT_RISK_PROFILE.maxRiskPct,
    };
  } catch {
    return DEFAULT_RISK_PROFILE;
  }
}

export function getRiskProfile(): RiskProfile {
  return readRiskProfile();
}

export function useRiskProfile(): [RiskProfile, (patch: Partial<RiskProfile>) => void] {
  const [profile, setProfile] = useState<RiskProfile>(() => readRiskProfile());
  useEffect(() => {
    const sync = () => setProfile(readRiskProfile());
    window.addEventListener("storage", sync);
    window.addEventListener("delta-terminal:prefs-changed", sync);
    return () => {
      window.removeEventListener("storage", sync);
      window.removeEventListener("delta-terminal:prefs-changed", sync);
    };
  }, []);
  const update = (patch: Partial<RiskProfile>) => {
    const next = { ...readRiskProfile(), ...patch };
    window.localStorage.setItem(RISK_PROFILE_KEY, JSON.stringify(next));
    window.dispatchEvent(new Event("delta-terminal:prefs-changed"));
    setProfile(next);
  };
  return [profile, update];
}
