Documentation
pub mod msgs {

    use cosmwasm_schema::{cw_serde, QueryResponses};
    use cosmwasm_std::Decimal;
    use cw_asset::AssetInfo;

    use crate::{
        common::{AssetType, PriceType, UpdateOption},
        pool::definitions::{InterestType, LoanDurationType, SwapInfo},
    };

    use super::definitions::{Config, PoolInfo};

    #[cw_serde]
    pub struct InstantiateMsg {
        pub admin: String,
        pub code_id_pool: u64,
        pub code_id_cw20: Option<u64>,
        pub code_id_indexer: u64,
        pub code_id_oracle: u64,
        pub pyth_addr: Option<String>,
        pub collector_addr: String,
        pub close_position_fee: Decimal,
        pub protocol_fee: Decimal,
        pub autoclose_enable: bool,
        pub oracle_assets_precision_sub: u8
    }

    #[cw_serde]
    pub enum ExecuteMsg {
        CreatePool(CreatePoolMsg),
        UpdateConfig(UpdateConfigMsg),
        UpdatePoolConfig(UpdatePoolConfigMsg),
    }

    #[cw_serde]
    #[derive(QueryResponses)]
    pub enum QueryMsg {
        #[returns(Config)]
        Config {},
        #[returns(PoolInfo)]
        Pool { id: u64 },
        #[returns(Vec<PoolInfo>)]
        Pools {
            start_after: Option<u64>,
            limit: Option<u32>,
        },
        #[returns(PoolInfo)]
        PoolFromLp { lp: String },
    }

    #[cw_serde]
    pub struct MigrateMsg {}

    #[cw_serde]
    pub struct CreatePoolMsg {
        pub collateral: AssetInfo,
        pub core: AssetInfo,
        pub price_type: PriceType,
        pub interest_type: InterestType,
        pub loan_duration_type: LoanDurationType,
        pub initial_ltv: Decimal,
        pub lp_type: AssetType,
        pub allow_early_close_uncollateralized: bool,
        pub swap_info: SwapInfo,
    }

    #[cw_serde]
    #[derive(Default)]
    pub struct UpdateConfigMsg {
        pub admin: Option<String>,
        pub code_id_pool: Option<u64>,
        pub code_id_cw20: Option<UpdateOption<u64>>,
        pub oracle_addr: Option<String>,
        pub collector_addr: Option<String>,
        pub indexer_addr: Option<String>,
        pub close_position_fee: Option<Decimal>,
        pub protocol_fee: Option<Decimal>,
        pub autoclose_enable: Option<bool>,
    }

    #[cw_serde]
    #[derive(Default)]
    pub struct UpdatePoolConfigMsg {
        pub pool_id: u64,
        pub price_type: Option<PriceType>,
        pub interest_type: Option<InterestType>,
        pub loan_duration_type: Option<LoanDurationType>,
        pub initial_ltv: Option<Decimal>,
        pub allow_early_close_uncollateralized: Option<bool>,
        pub swap_info: Option<SwapInfo>,
        pub factory: Option<String>,
    }
}

pub mod definitions {
    use cosmwasm_schema::cw_serde;
    use cosmwasm_std::{Addr, Decimal, StdError, StdResult};

    use crate::{pool::definitions::PoolConfig, traits::AssertOwner};

    #[cw_serde]
    pub struct Config {
        pub admin: Addr,
        pub code_id_pool: u64,
        pub code_id_cw20: Option<u64>,
        pub counter_pool: u64,
        pub oracle_addr: Addr,
        pub collector_addr: Addr,
        pub indexer_addr: Addr,
        pub close_position_fee: Decimal,
        pub protocol_fee: Decimal,
        pub autoclose_enable: bool,
    }

    #[allow(clippy::too_many_arguments)]
    impl Config {
        pub fn new(
            admin: Addr,
            code_id_pool: u64,
            collector_addr: Addr,
            code_id_cw20: Option<u64>,
            close_position_fee: Decimal,
            protocol_fee: Decimal,
            autoclose_enable: bool,
        ) -> Config {
            Config {
                admin,
                code_id_pool,
                counter_pool: 0,
                oracle_addr: Addr::unchecked(""),
                collector_addr,
                code_id_cw20,
                indexer_addr: Addr::unchecked(""),
                close_position_fee,
                protocol_fee,
                autoclose_enable,
            }
        }

        pub fn validate(&self) -> StdResult<()> {
            if self.close_position_fee > Decimal::one() {
                return Err(StdError::generic_err(
                    "close_position_fee must be lesser then or equal 1",
                ));
            }

            if self.protocol_fee > Decimal::one() {
                return Err(StdError::generic_err(
                    "protocol_fee must be lesser then or equal 1",
                ));
            }

            Ok(())
        }
    }

    impl AssertOwner for Config {
        fn get_admin(&self) -> Addr {
            self.admin.clone()
        }
    }

    #[cw_serde]
    pub struct PoolInfo {
        pub config: PoolConfig,
        pub address: Addr,
        pub id: u64,
    }
}

#[cfg(test)]

mod test {
    use rhaki_cw_plus::math::IntoDecimal;

    use crate::{
        common::{AssetType, PriceType},
        factory::msgs::{CreatePoolMsg, ExecuteMsg},
        pool::definitions::{LoanDurationType, SwapInfo},
    };

    #[test]
    pub fn test() {
        let a = ExecuteMsg::CreatePool(CreatePoolMsg {
            collateral: cw_asset::AssetInfoBase::Native("usdc".to_string()),
            core: cw_asset::AssetInfoBase::Native("btc".to_string()),
            price_type: PriceType::Oracle,
            interest_type: crate::pool::definitions::InterestType::Quadratic {
                a: "100".into_decimal(),
                c: "5".into_decimal(),
            },
            loan_duration_type: LoanDurationType::Fixed(30 * 86_400),
            initial_ltv: "0.7".into_decimal(),
            lp_type: AssetType::Token,
            allow_early_close_uncollateralized: false,
            swap_info: SwapInfo::OnlyFromcore {
                fee: "0.05".into_decimal(),
            },
        });

        let b = serde_json::to_string_pretty(&a).unwrap();

        println!("{b}")
    }
}