/**
 * Domain types for the cross-exchange BTC arbitrage engine.
 * All prices are quoted in USDT (BTC/USDT on every exchange — apples-to-apples,
 * no USD/USDT basis distortion).
 */

export type ExchangeId = "kraken" | "bybit" | "okx" | "binance";

export const EXCHANGE_IDS: ExchangeId[] = ["kraken", "bybit", "okx", "binance"];

/** A single order book price level. */
export interface Level {
  price: number;
  qty: number;
}

/** Normalized order book for one exchange. Bids desc, asks asc. */
export interface OrderBook {
  exchange: ExchangeId;
  bids: Level[];
  asks: Level[];
  /** Local receive timestamp (ms epoch). */
  recvTs: number;
  /** Exchange-provided timestamp if available (ms epoch). */
  exchangeTs: number | null;
}

/** Connection status of an exchange feed. */
export type FeedStatus = "connecting" | "live" | "stale" | "down";

/** Best bid/ask snapshot exposed to the UI. */
export interface BestQuote {
  exchange: ExchangeId;
  bid: number | null;
  bidQty: number | null;
  ask: number | null;
  askQty: number | null;
  recvTs: number | null;
  status: FeedStatus;
  /** ms since last update. */
  ageMs: number | null;
}

/**
 * Why an opportunity was or wasn't executed.
 * Exhaustive union — handle every case.
 */
export type OpportunityStatus =
  | "executed"
  | "executed_partial"
  | "rejected_fees"
  | "rejected_liquidity"
  | "rejected_risk"
  | "rejected_flicker"
  | "rejected_stale"
  | "pending_confirm";

export interface Opportunity {
  id: string;
  ts: number;
  buyExchange: ExchangeId;
  sellExchange: ExchangeId;
  /** Best (top-of-book) ask on the buy side, before walking depth. */
  topBuyAsk: number;
  /** Best (top-of-book) bid on the sell side, before walking depth. */
  topSellBid: number;
  /** Volume actually evaluated (BTC), after liquidity + wallet caps. */
  volumeBtc: number;
  /** Volume-weighted average buy price for volumeBtc. */
  buyVwap: number;
  /** Volume-weighted average sell price for volumeBtc. */
  sellVwap: number;
  grossSpread: number;
  grossSpreadPct: number;
  feeBuy: number;
  feeSell: number;
  netProfit: number;
  netProfitPct: number;
  status: OpportunityStatus;
  reason: string;
  /** True when generated by the synthetic demo injector. */
  demo: boolean;
}

/** An executed (simulated) trade. */
export interface Trade {
  id: string;
  ts: number;
  buyExchange: ExchangeId;
  sellExchange: ExchangeId;
  volumeBtc: number;
  requestedBtc: number;
  buyVwap: number;
  sellVwap: number;
  /** Buy VWAP after simulated latency drift. */
  execBuyVwap: number;
  /** Sell VWAP after simulated latency drift. */
  execSellVwap: number;
  feeBuy: number;
  feeSell: number;
  /** Net realized P&L in USDT (negative = loss). */
  netProfit: number;
  netProfitPct: number;
  partial: boolean;
  demo: boolean;
}

/** Per-exchange simulated wallet (pre-positioned inventory model). */
export interface Wallet {
  exchange: ExchangeId;
  usdt: number;
  btc: number;
}

export interface RebalanceEvent {
  id: string;
  ts: number;
  fromExchange: ExchangeId;
  toExchange: ExchangeId;
  asset: "BTC" | "USDT";
  amount: number;
  withdrawalFee: number;
  reason: string;
}

export type CircuitState = "running" | "paused" | "tripped";

export interface EngineStats {
  uptimeMs: number;
  ticksProcessed: number;
  opportunitiesDetected: number;
  tradesExecuted: number;
  tradesRejected: number;
  realizedPnl: number;
  consecutiveLosses: number;
  circuit: CircuitState;
  demoMode: boolean;
  /** Average engine processing time per tick (ms). */
  avgTickMs: number;
}

/** Full snapshot pushed to the dashboard over SSE. */
export interface StateSnapshot {
  ts: number;
  quotes: BestQuote[];
  wallets: Wallet[];
  stats: EngineStats;
  recentOpportunities: Opportunity[];
  recentTrades: Trade[];
  rebalances: RebalanceEvent[];
  pnlSeries: PnlPoint[];
  config: PublicConfig;
}

export interface PnlPoint {
  ts: number;
  pnl: number;
}

/** Partial update body for PATCH /api/config. */
export interface ConfigPatch {
  minNetProfitPct?: number;
  maxTradeBtc?: number;
  flickerConfirmMs?: number;
  activeExchanges?: Partial<Record<ExchangeId, boolean>>;
}

/** Engine config surfaced to the UI (no secrets). */
export interface PublicConfig {
  minNetProfitPct: number;
  maxTradeBtc: number;
  staleMs: number;
  flickerConfirmMs: number;
  latencyMs: number;
  activeExchanges: Record<ExchangeId, boolean>;
  defaults: {
    minNetProfitPct: number;
    maxTradeBtc: number;
    flickerConfirmMs: number;
    activeExchanges: Record<ExchangeId, boolean>;
  };
  takerFees: Record<ExchangeId, number>;
  withdrawalFeesBtc: Record<ExchangeId, number>;
}
