use anyhow::Result;
use riptide_amm::MarketUpdateType;

use crate::config::{Command, Config, MarketCommand, MarketSetCommand, OracleCommand};

mod oracle_update;

mod swap;

mod market_close;
mod market_deposit;
mod market_initialize;
mod market_list;
mod market_update;
mod market_withdraw;

mod version;

pub fn handle(config: &Config) -> Result<()> {
    match &config.command {
        Command::Version => version::handle(config)?,
        Command::Oracle { command } => match command {
            OracleCommand::Update { market, price } => {
                oracle_update::handle(config, market, price)?
            }
        },
        Command::Swap {
            market,
            amount_in,
            amount_out,
            amount_is_token_a,
        } => {
            if let Some(amount_in) = amount_in {
                swap::handle(
                    config,
                    market,
                    amount_in,
                    amount_is_token_a,
                    &true,
                    &config.yes,
                )?
            } else if let Some(amount_out) = amount_out {
                swap::handle(
                    config,
                    market,
                    amount_out,
                    amount_is_token_a,
                    &false,
                    &config.yes,
                )?
            } else {
                return Err(anyhow::anyhow!(
                    "Either amount_in or amount_out must be specified"
                ));
            }
        }
        Command::Market { command } => match command {
            MarketCommand::List => market_list::handle(config)?,
            MarketCommand::Init { mint_a, mint_b } => {
                market_initialize::handle(config, mint_a, mint_b)?
            }
            MarketCommand::Deposit {
                market,
                amount_a,
                amount_b,
            } => market_deposit::handle(config, market, amount_a, amount_b)?,
            MarketCommand::Withdraw {
                market,
                amount_a,
                amount_b,
            } => market_withdraw::handle(config, market, amount_a, amount_b)?,
            MarketCommand::Set { command } => match command {
                MarketSetCommand::Authority {
                    market,
                    new_authority,
                } => market_update::handle(
                    config,
                    market,
                    &MarketUpdateType::Authority(*new_authority),
                )?,
                MarketSetCommand::Updater {
                    market,
                    new_updater,
                } => {
                    market_update::handle(config, market, &MarketUpdateType::Updater(*new_updater))?
                }
                MarketSetCommand::MaxInventoryImbalancePerCent {
                    market,
                    new_max_inventory_imbalance_guard_per_cent,
                } => market_update::handle(
                    config,
                    market,
                    &MarketUpdateType::MaxInventoryImbalancePerCent(
                        *new_max_inventory_imbalance_guard_per_cent,
                    ),
                )?,
                MarketSetCommand::MinSpreadPer1M {
                    market,
                    new_min_spread_guard_per_m,
                } => market_update::handle(
                    config,
                    market,
                    &MarketUpdateType::MinSpreadPerM(*new_min_spread_guard_per_m),
                )?,
                MarketSetCommand::ArbPenaltyPer1M {
                    market,
                    new_arb_penalty_per_m,
                } => market_update::handle(
                    config,
                    market,
                    &MarketUpdateType::ArbPenaltyPerM(*new_arb_penalty_per_m),
                )?,
                MarketSetCommand::JitodontfrontPenaltyPer1M {
                    market,
                    new_jitodontfront_penalty_per_m,
                } => market_update::handle(
                    config,
                    market,
                    &MarketUpdateType::JitodontfrontPenaltyPerM(*new_jitodontfront_penalty_per_m),
                )?,
                MarketSetCommand::MinOraclePrice {
                    market,
                    new_min_oracle_price_guard,
                } => market_update::handle(
                    config,
                    market,
                    &MarketUpdateType::MinOraclePrice(*new_min_oracle_price_guard),
                )?,
                MarketSetCommand::MaxOraclePrice {
                    market,
                    new_max_oracle_price_guard,
                } => market_update::handle(
                    config,
                    market,
                    &MarketUpdateType::MaxOraclePrice(*new_max_oracle_price_guard),
                )?,
                MarketSetCommand::SkewCliffMinPer1M {
                    market,
                    new_skew_cliff_min_per_m,
                } => market_update::handle(
                    config,
                    market,
                    &MarketUpdateType::SkewCliffMinPerM(*new_skew_cliff_min_per_m),
                )?,
                MarketSetCommand::SkewCliffMaxPer1M {
                    market,
                    new_skew_cliff_max_per_m,
                } => market_update::handle(
                    config,
                    market,
                    &MarketUpdateType::SkewCliffMaxPerM(*new_skew_cliff_max_per_m),
                )?,
                MarketSetCommand::MaxAInventoryPer1M {
                    market,
                    new_max_a_inventory_per_m,
                } => market_update::handle(
                    config,
                    market,
                    &MarketUpdateType::MaxAInventoryPerM(*new_max_a_inventory_per_m),
                )?,
                MarketSetCommand::MaxBInventoryPer1M {
                    market,
                    new_max_b_inventory_per_m,
                } => market_update::handle(
                    config,
                    market,
                    &MarketUpdateType::MaxBInventoryPerM(*new_max_b_inventory_per_m),
                )?,
            },
            MarketCommand::Close { market } => market_close::handle(config, market)?,
        },
    };

    Ok(())
}
