//! Farms Client

use crate::dex::types::*;
use reqwest::Client;
use serde_json::json;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

/// Farms sub-client
pub struct FarmsClient {
    config: DexConfig,
    client: Client,
    closed: Arc<AtomicBool>,
}

impl FarmsClient {
    pub(crate) fn new(config: DexConfig, client: Client, closed: Arc<AtomicBool>) -> Self {
        Self { config, client, closed }
    }

    /// List all farms
    pub async fn list_farms(&self) -> Result<Vec<Farm>, DexError> {
        self.get("/farms").await
    }

    /// Get a specific farm
    pub async fn get_farm(&self, farm_id: &str) -> Result<Farm, DexError> {
        self.get(&format!("/farms/{}", farm_id)).await
    }

    /// Stake tokens in a farm
    pub async fn stake(&self, params: StakeParams) -> Result<FarmPosition, DexError> {
        self.post("/farms/stake", json!({
            "farm": params.farm,
            "amount": params.amount,
        })).await
    }

    /// Unstake tokens from a farm
    pub async fn unstake(&self, farm: &str, amount: &str) -> Result<FarmPosition, DexError> {
        self.post("/farms/unstake", json!({
            "farm": farm,
            "amount": amount,
        })).await
    }

    /// Claim rewards from a farm
    pub async fn claim_rewards(&self, farm: &str) -> Result<ClaimRewardsResult, DexError> {
        self.post("/farms/claim", json!({
            "farm": farm,
        })).await
    }

    /// Get all farm positions
    pub async fn get_my_farm_positions(&self) -> Result<Vec<FarmPosition>, DexError> {
        self.get("/farms/positions").await
    }

    // Internal methods

    async fn get<T: serde::de::DeserializeOwned>(&self, path: &str) -> Result<T, DexError> {
        if self.closed.load(Ordering::SeqCst) {
            return Err(DexError::ClientClosed);
        }

        let url = format!("{}{}", self.config.endpoint, path);
        let response = self.client
            .get(&url)
            .header("Content-Type", "application/json")
            .header("Authorization", format!("Bearer {}", self.config.api_key))
            .header("X-SDK-Version", "rust/0.1.0")
            .send()
            .await?;

        if !response.status().is_success() {
            return Err(DexError::Http {
                message: format!("HTTP {}", response.status()),
                code: None,
                status: Some(response.status().as_u16()),
            });
        }

        response.json().await.map_err(DexError::from)
    }

    async fn post<T: serde::de::DeserializeOwned>(&self, path: &str, body: serde_json::Value) -> Result<T, DexError> {
        if self.closed.load(Ordering::SeqCst) {
            return Err(DexError::ClientClosed);
        }

        let url = format!("{}{}", self.config.endpoint, path);
        let response = self.client
            .post(&url)
            .header("Content-Type", "application/json")
            .header("Authorization", format!("Bearer {}", self.config.api_key))
            .header("X-SDK-Version", "rust/0.1.0")
            .json(&body)
            .send()
            .await?;

        if !response.status().is_success() {
            return Err(DexError::Http {
                message: format!("HTTP {}", response.status()),
                code: None,
                status: Some(response.status().as_u16()),
            });
        }

        response.json().await.map_err(DexError::from)
    }
}
