use anyhow::anyhow;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct StringParams {
    planner: String,
    info: String,
    mint_impl: String,
    swap_impl: String,
}

pub(crate) struct Params {
    pub planner: Vec<u8>,
    #[allow(dead_code)] // We keep the unused info field for future pricing/view operations
    pub info: Vec<u8>,
    pub mint_impl: Vec<u8>,
    pub swap_impl: Vec<u8>,
}

impl StringParams {
    pub fn parse(input: &str) -> anyhow::Result<Self> {
        serde_qs::from_str(input).map_err(|e| anyhow!("Failed to parse query params: {}", e))
    }
}

impl Params {
    pub fn parse(input: &str) -> anyhow::Result<Self> {
        let params = StringParams::parse(input)?;

        fn decode_addr(s: &str) -> anyhow::Result<Vec<u8>> {
            let s = s.strip_prefix("0x").unwrap_or(s);
            if s.len() != 40 {
                return Err(anyhow!("address must be 20 bytes (40 hex chars), got len={}", s.len()));
            }
            let bytes = hex::decode(s)?;
            if bytes.len() != 20 {
                return Err(anyhow!("decoded address is not 20 bytes"));
            }
            Ok(bytes)
        }

        Ok(Self {
            planner: decode_addr(&params.planner)?,
            info: decode_addr(&params.info)?,
            mint_impl: decode_addr(&params.mint_impl)?,
            swap_impl: decode_addr(&params.swap_impl)?,
        })
    }
}
