//! Polygon (US equities) endpoints. Historical + quote only — Polygon has no
//! company profile or financial statements upstream.

use motosan_finance::{EquityHistoricalData, EquityQuoteData, FinanceResult};
use motosan_finance_polygon::NewsArticle;
use serde::Serialize;

use crate::client::FinProxy;
use crate::equity::{HistoricalParams, SymbolParams};
use crate::error::SdkError;

/// `?symbol=&limit=` for Polygon news (both optional; server defaults limit to 10).
#[derive(Debug, Clone, Serialize, Default)]
pub struct NewsParams {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub symbol: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub limit: Option<u32>,
}

impl NewsParams {
    pub fn new() -> Self {
        Self::default()
    }
    pub fn symbol(mut self, s: impl Into<String>) -> Self {
        self.symbol = Some(s.into());
        self
    }
    pub fn limit(mut self, n: u32) -> Self {
        self.limit = Some(n);
        self
    }
}

/// Polygon sub-client, obtained via [`FinProxy::polygon`].
pub struct Polygon<'a> {
    pub(crate) client: &'a FinProxy,
}

impl FinProxy {
    /// Access the Polygon (US equities) endpoints.
    pub fn polygon(&self) -> Polygon<'_> {
        Polygon { client: self }
    }
}

impl Polygon<'_> {
    /// GET /v1/polygon/equity/price/historical
    pub async fn historical(
        &self,
        params: &HistoricalParams,
    ) -> Result<FinanceResult<Vec<EquityHistoricalData>>, SdkError> {
        self.client.get("/v1/polygon/equity/price/historical", params).await
    }

    /// GET /v1/polygon/equity/price/quote
    pub async fn quote(
        &self,
        params: &SymbolParams,
    ) -> Result<FinanceResult<Vec<EquityQuoteData>>, SdkError> {
        self.client.get("/v1/polygon/equity/price/quote", params).await
    }

    /// GET /v1/polygon/news
    pub async fn news(&self, params: &NewsParams) -> Result<Vec<NewsArticle>, SdkError> {
        self.client.get("/v1/polygon/news", params).await
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use wiremock::matchers::{method, path, query_param};
    use wiremock::{Mock, MockServer, ResponseTemplate};

    #[tokio::test]
    async fn quote_hits_polygon_path_and_unwraps() {
        let server = MockServer::start().await;
        let body = r#"{"success":true,"data":{"results":[],"provider":"polygon",
            "warnings":[],"extra":{}},"meta":{}}"#;
        Mock::given(method("GET"))
            .and(path("/v1/polygon/equity/price/quote"))
            .and(query_param("symbol", "AAPL"))
            .respond_with(ResponseTemplate::new(200).set_body_string(body))
            .mount(&server)
            .await;

        let client = FinProxy::new(server.uri()).unwrap();
        let res = client.polygon().quote(&SymbolParams::new("AAPL")).await.unwrap();
        assert_eq!(res.provider.as_deref(), Some("polygon"));
    }

    #[tokio::test]
    async fn historical_encodes_optional_params() {
        let server = MockServer::start().await;
        let body = r#"{"success":true,"data":{"results":[],"provider":"polygon",
            "warnings":[],"extra":{}},"meta":{}}"#;
        Mock::given(method("GET"))
            .and(path("/v1/polygon/equity/price/historical"))
            .and(query_param("symbol", "AAPL"))
            .and(query_param("start", "2024-01-02"))
            .and(query_param("end", "2024-01-10"))
            .respond_with(ResponseTemplate::new(200).set_body_string(body))
            .mount(&server)
            .await;

        let client = FinProxy::new(server.uri()).unwrap();
        let res = client
            .polygon()
            .historical(&HistoricalParams::new("AAPL").start("2024-01-02").end("2024-01-10"))
            .await
            .unwrap();
        assert_eq!(res.provider.as_deref(), Some("polygon"));
    }

    #[tokio::test]
    async fn news_encodes_limit_and_unwraps_list() {
        let server = MockServer::start().await;
        // News returns a bare `data: []` envelope (like sec().filings()).
        let body = r#"{"success":true,"data":[],"meta":{}}"#;
        Mock::given(method("GET"))
            .and(path("/v1/polygon/news"))
            .and(query_param("symbol", "AAPL"))
            .and(query_param("limit", "5"))
            .respond_with(ResponseTemplate::new(200).set_body_string(body))
            .mount(&server)
            .await;

        let client = FinProxy::new(server.uri()).unwrap();
        let rows = client
            .polygon()
            .news(&NewsParams::new().symbol("AAPL").limit(5))
            .await
            .unwrap();
        assert!(rows.is_empty());
    }
}
