use std::{num::NonZeroU64, result, sync::Arc};
use thiserror::Error;
use uuid::Uuid;
use lnm_sdk::api_v3::error::{PriceValidationError, RestApiError, TradeValidationError};
use crate::{
db::error::DbError,
sync::{SyncMode, process::error::SyncProcessFatalError},
};
use super::{
super::super::error::TradeCoreError,
state::{LiveTradeExecutorStatus, LiveTradeExecutorStatusNotReady},
};
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum ExecutorActionError {
#[error("[RestApi] {0}")]
RestApi(#[from] RestApiError),
#[error("Balance is too low error")]
BalanceTooLow,
#[error("[Db] {0}")]
Db(#[from] DbError),
#[error("Db is empty error")]
DbIsEmpty,
#[error("Stoploss evaluation error")]
StoplossEvaluation(TradeCoreError),
#[error("New Trade {trade_id} is not running")]
NewTradeNotRunning { trade_id: Uuid },
#[error("Trade {trade_id} is already registered")]
TradeAlreadyRegistered { trade_id: Uuid },
#[error("Price Trigger update error")]
PriceTriggerUpdate(TradeCoreError),
#[error("Closed history update error")]
ClosedHistoryUpdate(TradeCoreError),
#[error("Updated trades {trade_ids:?} not running")]
UpdatedTradesNotRunning { trade_ids: Vec<Uuid> },
#[error("Trade {trade_id} is not closed")]
TradeNotClosed { trade_id: Uuid },
#[error("Trade {trade_id} is not registered")]
TradeNotRegistered { trade_id: Uuid },
#[error("Live trade executor is not ready. No session.")]
ExecutorNotReadyNoSession,
#[error("Live trade executor is not ready: {0}")]
ExecutorNotReady(LiveTradeExecutorStatusNotReady),
#[error("[InvalidMarketPrice] {0}")]
InvalidMarketPrice(PriceValidationError),
#[error("Invalid trade params error {0}")]
InvalidTradeParams(TradeValidationError),
#[error("Max running trades ({max_qtd}) reached")]
MaxRunningTradesReached { max_qtd: usize },
#[error("Margin amount {amount} exceeds maximum amount {max_amount} for trade")]
MarginAmountExceedsMaxForTrade { amount: NonZeroU64, max_amount: u64 },
#[error("Cash-in amount {amount} exceeds maximum cash-in {max_cash_in} for trade")]
CashInAmountExceedsMaxForTrade {
amount: NonZeroU64,
max_cash_in: u64,
},
#[error("Unexpected closed trade returned by the server. Id: {trade_id}")]
UnexpectedClosedTrade { trade_id: Uuid },
#[error("Closed trade not confirmed by the server. Id: {trade_id}")]
ClosedTradeNotConfirmed { trade_id: Uuid },
}
pub(super) type ExecutorActionResult<T> = result::Result<T, ExecutorActionError>;
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum ExecutorProcessRecoverableError {
#[error("Live Trade Session evaluation error {0}")]
LiveTradeSessionEvaluation(ExecutorActionError),
#[error("`SyncRecvLagged` error, skipped: {skipped}")]
SyncRecvLagged { skipped: u64 },
}
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum ExecutorProcessFatalError {
#[error("`Sync` process (dependency) was terminated with error: {0}")]
SyncProcessTerminated(Arc<SyncProcessFatalError>),
#[error("Failed to close trades on shutdown: {0}")]
FailedToCloseTradesOnShutdown(ExecutorActionError),
#[error("`Sync` process (dependency) was shutdown")]
SyncProcessShutdown,
#[error("`SyncRecvClosed` error")]
SyncRecvClosed,
}
pub(super) type ExecutorProcessFatalResult<T> = result::Result<T, ExecutorProcessFatalError>;
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum LiveTradeExecutorError {
#[error("REST API client initialization error: {0}")]
RestApiInit(RestApiError),
#[error("Sync engine live price feed is not active. Mode: {0}")]
SyncEngineLiveFeedInactive(SyncMode),
#[error("Launch clean up error {0}")]
LaunchCleanUp(ExecutorActionError),
#[error("Launch account resolution error {0}")]
LaunchAccountResolution(ExecutorActionError),
#[error("API credentials were not set")]
ApiCredentialsNotSet,
#[error("Executor process already consumed")]
ExecutorProcessAlreadyConsumed,
#[error("Executor process already terminated error, status: {0}")]
ExecutorProcessAlreadyTerminated(LiveTradeExecutorStatus),
#[error("Executor shutdown procedure failed: {0}")]
ExecutorShutdownFailed(Arc<ExecutorProcessFatalError>),
}
pub(super) type LiveTradeExecutorResult<T> = result::Result<T, LiveTradeExecutorError>;