use crate::error::AppError;
use crate::mapping::{map_financial_statements, map_profile};
use common_contracts::dtos::{CompanyProfileDto, TimeSeriesFinancialDto};
use anyhow::anyhow;

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

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

    pub async fn fetch_all_data(
        &self,
        symbol: &str,
    ) -> Result<(CompanyProfileDto, Vec<TimeSeriesFinancialDto>), AppError> {
        let (summary_raw, financials_raw) = self.fetch_raw_data(symbol).await?;
        let profile = map_profile(&summary_raw, symbol)?;
        let financials = map_financial_statements(&financials_raw, symbol)?;
        Ok((profile, financials))
    }

    async fn fetch_raw_data(
        &self,
        symbol: &str,
    ) -> Result<(serde_json::Value, serde_json::Value), AppError> {
        // Yahoo quoteSummary: assetProfile + quoteType
        let summary_url = format!(
            "https://query1.finance.yahoo.com/v10/finance/quoteSummary/{}?modules=assetProfile,quoteType",
            symbol
        );
        // Yahoo financials: income/balance/cashflow histories
        let financials_url = format!(
            "https://query1.finance.yahoo.com/v10/finance/quoteSummary/{}?modules=incomeStatementHistory,balanceSheetHistory,cashflowStatementHistory",
            symbol
        );

        let summary_task = self.client.get(&summary_url).send();
        let financials_task = self.client.get(&financials_url).send();

        let (summary_res, financials_res) = tokio::try_join!(summary_task, financials_task)
            .map_err(|e| AppError::ServiceRequest(e))?;

        let summary_res = summary_res.error_for_status()?;
        let financials_res = financials_res.error_for_status()?;

        let summary_json: serde_json::Value = summary_res
            .json()
            .await
            .map_err(|e| AppError::DataParsing(anyhow!(e)))?;
        let financials_json: serde_json::Value = financials_res
            .json()
            .await
            .map_err(|e| AppError::DataParsing(anyhow!(e)))?;

        Ok((summary_json, financials_json))
    }
}
