import { buildProxyDispatcher } from "../accounts/client-factory.js";
import { findRowById } from "../accounts/repository.js";
import type { ExchangeAccountRow } from "../accounts/types.js";
import { decrypt } from "../crypto/secretbox.js";
import { BinanceC2CClient } from "../binance/client.js";
import { BinanceExchangeClient } from "../binance/adapter.js";
import { BybitClient } from "../bybit/client.js";
import { BybitExchangeClient } from "../bybit/adapter.js";
import type { ExchangeClient } from "./client.js";

export type { ExchangeClient } from "./client.js";
export * from "./types.js";

/**
 * Resolve o cliente neutro (`ExchangeClient`) de uma conta: decifra o secret,
 * pluga o proxy da conta e instancia o adapter da exchange correta. É a única
 * porta para a lógica de negócio falar com qualquer exchange.
 */
export function buildExchangeClient(row: ExchangeAccountRow): ExchangeClient {
  const dispatcher = buildProxyDispatcher(row);
  const secret = decrypt(row.api_secret_enc);

  if (row.exchange === "binance") {
    const client = new BinanceC2CClient({
      apiKey: row.api_key,
      secretKey: secret,
      userId: row.binance_user_id ?? "",
      dispatcher,
    });
    return new BinanceExchangeClient(row.id, client);
  }

  if (row.exchange === "bybit") {
    const client = new BybitClient({
      apiKey: row.api_key,
      secretKey: secret,
      dispatcher,
    });
    // `binance_user_id` é reaproveitado como id próprio na Bybit quando
    // preenchido (usado p/ direção do chat). Opcional.
    return new BybitExchangeClient(row.id, client, row.binance_user_id ?? null);
  }

  throw new Error(`Exchange não suportada: ${row.exchange}`);
}

/** Conveniência: carrega a conta por id e devolve o ExchangeClient. */
export async function exchangeClientForAccount(id: number): Promise<ExchangeClient> {
  const row = await findRowById(id);
  if (!row) throw new Error(`Conta ${id} não encontrada.`);
  return buildExchangeClient(row);
}
