//!
//! 数据持久化客户端
//!
//! 提供一个类型化的接口，用于与 `data-persistence-service` 进行通信。
//!

use crate::error::Result;
use common_contracts::{
    config_models::{AnalysisTemplateSets, LlmProvidersConfig},
    dtos::{
        CompanyProfileDto, NewAnalysisResult, RealtimeQuoteDto, TimeSeriesFinancialBatchDto,
        TimeSeriesFinancialDto,
    },
};
use tracing::info;

#[derive(Clone)]
pub struct PersistenceClient {
    client: reqwest::Client,
    base_url: String,
}

impl PersistenceClient {
    pub fn new(base_url: String) -> Self {
        Self {
            client: reqwest::Client::new(),
            base_url,
        }
    }

    pub async fn get_company_profile(&self, symbol: &str) -> Result<CompanyProfileDto> {
        let url = format!("{}/companies/{}", self.base_url, symbol);
        info!("Fetching company profile for {} from {}", symbol, url);
        let dto = self
            .client
            .get(&url)
            .send()
            .await?
            .error_for_status()?
            .json::<CompanyProfileDto>()
            .await?;
        Ok(dto)
    }

    pub async fn get_financial_statements(
        &self,
        symbol: &str,
    ) -> Result<Vec<TimeSeriesFinancialDto>> {
        let url = format!("{}/market-data/financial-statements/{}", self.base_url, symbol);
        info!("Fetching financials for {} from {}", symbol, url);
        let dtos = self
            .client
            .get(&url)
            .send()
            .await?
            .error_for_status()?
            .json::<Vec<TimeSeriesFinancialDto>>()
            .await?;
        Ok(dtos)
    }

    // --- Config Fetching Methods ---

    pub async fn get_llm_providers_config(&self) -> Result<LlmProvidersConfig> {
        let url = format!("{}/configs/llm_providers", self.base_url);
        info!("Fetching LLM providers config from {}", url);
        let config = self
            .client
            .get(&url)
            .send()
            .await?
            .error_for_status()?
            .json::<LlmProvidersConfig>()
            .await?;
        Ok(config)
    }

    pub async fn get_analysis_template_sets(&self) -> Result<AnalysisTemplateSets> {
        let url = format!("{}/configs/analysis_template_sets", self.base_url);
        info!("Fetching analysis template sets from {}", url);
        let config = self
            .client
            .get(&url)
            .send()
            .await?
            .error_for_status()?
            .json::<AnalysisTemplateSets>()
            .await?;
        Ok(config)
    }

    // --- Data Writing Methods ---

    pub async fn create_analysis_result(&self, result: NewAnalysisResult) -> Result<()> {
        let url = format!("{}/analysis-results", self.base_url);
        info!(
            "Persisting analysis result for symbol '{}', module '{}' to {}",
            result.symbol, result.module_id, url
        );
        self.client
            .post(&url)
            .json(&result)
            .send()
            .await?
            .error_for_status()?;
        Ok(())
    }

    pub async fn upsert_company_profile(&self, profile: CompanyProfileDto) -> Result<()> {
        let url = format!("{}/companies", self.base_url);
        info!("Upserting company profile for {} to {}", profile.symbol, url);
        self.client
            .put(&url)
            .json(&profile)
            .send()
            .await?
            .error_for_status()?;
        Ok(())
    }

    pub async fn upsert_realtime_quote(&self, quote: RealtimeQuoteDto) -> Result<()> {
        let url = format!("{}/market-data/quotes", self.base_url);
        info!("Upserting realtime quote for {} to {}", quote.symbol, url);
        self.client
            .post(&url)
            .json(&quote)
            .send()
            .await?
            .error_for_status()?;
        Ok(())
    }

    pub async fn batch_insert_financials(&self, dtos: Vec<TimeSeriesFinancialDto>) -> Result<()> {
        if dtos.is_empty() {
            return Ok(());
        }
        let url = format!("{}/market-data/financials/batch", self.base_url);
        let symbol = dtos[0].symbol.clone();
        info!(
            "Batch inserting {} financial statements for {} to {}",
            dtos.len(),
            symbol,
            url
        );

        let batch = TimeSeriesFinancialBatchDto { records: dtos };

        self.client
            .post(&url)
            .json(&batch)
            .send()
            .await?
            .error_for_status()?;

        Ok(())
    }
}
