package xyz.kusoft.tradebotmonitor

import org.json.JSONObject

data class Candle(
    val timestamp: Long,
    val open: Double,
    val high: Double,
    val low: Double,
    val close: Double,
    val volume: Double,
    val ema50: Double?,
    val ema200: Double?,
    val rsi14: Double?,
    val atr14: Double?,
    val macd: Double?,
    val macdSignal: Double?,
)

data class TickerData(
    val symbol: String,
    val lastPrice: Double,
    val bid: Double,
    val ask: Double,
    val turnover24h: Double,
    val volume24h: Double,
    val change24h: Double,
    val spreadPercent: Double,
)

data class FeatureItem(
    val group: String,
    val label: String,
    val rawDisplay: String,
    val modelDisplay: String,
    val interpretation: String,
)

data class ForecastData(
    val model: String,
    val expectedReturnPercent: Double,
    val probabilityUp: Double,
    val skill: Double,
    val volatilityPercent: Double,
    val horizon: Int,
    val q10Percent: Double,
    val q50Percent: Double,
    val q90Percent: Double,
    val qualityGatePassed: Boolean?,
    val reason: String,
    val features: List<FeatureItem>,
)

data class MarketItem(
    val symbol: String,
    val ticker: TickerData?,
    val candles: List<Candle>,
    val forecast: ForecastData?,
    val qualityStatus: String,
    val qualityScore: Double,
)

data class SignalData(
    val symbol: String,
    val action: String,
    val confidence: Double,
    val reason: String,
    val diagnostics: JSONObject,
) {
    val expectedReturnPercent: Double
        get() = diagnostics.optDoubleOrNull("expected_return_percent")
            ?: diagnostics.optJSONObject("forecast")?.optDoubleOrNull("expected_return_percent")
            ?: 0.0

    val probabilityUp: Double
        get() = diagnostics.optDoubleOrNull("probability_up")
            ?: diagnostics.optJSONObject("forecast")?.optDoubleOrNull("probability_up")
            ?: 0.0

    val positionNotionalUsdt: Double
        get() = diagnostics.optDoubleOrNull("position_notional_usdt")
            ?: diagnostics.optJSONObject("position_sizing")?.optDoubleOrNull("notional_usdt")
            ?: 0.0
}

data class PositionData(
    val id: Long?,
    val symbol: String,
    val qty: Double,
    val entryPrice: Double,
    val markPrice: Double,
    val notionalUsdt: Double,
    val marketValue: Double,
    val unrealizedPnl: Double,
    val unrealizedPnlPercent: Double,
    val stopLoss: Double?,
    val takeProfit: Double?,
    val highestPrice: Double?,
    val trailingStop: Double?,
    val atrTrailingStop: Double?,
    val openedAt: String,
    val exitAction: String,
    val exitReason: String,
    val stopLossExitEnabled: Boolean,
)

data class AccountData(
    val equity: Double,
    val cash: Double,
    val exposure: Double,
)

data class ClosedTradeData(
    val symbol: String,
    val qty: Double,
    val entryPrice: Double?,
    val exitPrice: Double?,
    val grossPnl: Double,
    val feeUsdt: Double,
    val netPnl: Double,
    val reason: String,
    val openedAt: String,
    val closedAt: String,
)

data class ClosedTradesSummary(
    val trades: Int,
    val netPnl: Double,
    val grossPnl: Double,
    val feeUsdt: Double,
    val wins: Int,
    val losses: Int,
    val winRate: Double,
)

data class BotSnapshot(
    val ok: Boolean,
    val running: Boolean,
    val mode: String,
    val account: AccountData,
    val positions: List<PositionData>,
    val closedTrades: List<ClosedTradeData>,
    val closedTradesSummary: ClosedTradesSummary,
    val markets: List<MarketItem>,
    val signalsBySymbol: Map<String, SignalData>,
    val config: JSONObject,
    val retrain: JSONObject,
    val backtest: JSONObject,
    val fetchedAtMillis: Long,
)

fun JSONObject.optStringClean(name: String): String =
    if (isNull(name)) "" else optString(name, "")

fun JSONObject.optDoubleOrNull(name: String): Double? =
    if (has(name) && !isNull(name)) optDouble(name) else null

fun JSONObject.optLongOrNull(name: String): Long? =
    if (has(name) && !isNull(name)) optLong(name) else null

fun JSONObject.optBooleanOrNull(name: String): Boolean? =
    if (has(name) && !isNull(name)) optBoolean(name) else null
