//! Types for the Exa `/search` endpoint

use serde::Deserialize;
use serde::Serialize;

use super::common::ContentsOptions;
use super::common::LivecrawlOption;
use super::common::SearchResult;
use super::common::SearchType;

// Backward-compatible re-exports (CostDollars previously lived in this module)
pub use super::common::CostDollars;
pub use super::common::CostDollarsContents;
pub use super::common::CostDollarsSearch;

/// Request body for `POST /search`
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SearchRequest {
    /// The search query (natural language)
    pub query: String,

    /// Number of results to return (default: 10)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub num_results: Option<u32>,

    /// Type of search
    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
    pub search_type: Option<SearchType>,

    /// What content to include in results
    #[serde(skip_serializing_if = "Option::is_none")]
    pub contents: Option<ContentsOptions>,

    /// Include domains filter
    #[serde(skip_serializing_if = "Option::is_none")]
    pub include_domains: Option<Vec<String>>,

    /// Exclude domains filter
    #[serde(skip_serializing_if = "Option::is_none")]
    pub exclude_domains: Option<Vec<String>>,

    /// Start date filter (ISO 8601)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub start_published_date: Option<String>,

    /// End date filter (ISO 8601)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub end_published_date: Option<String>,

    /// Livecrawl option
    #[serde(skip_serializing_if = "Option::is_none")]
    pub livecrawl: Option<LivecrawlOption>,

    /// Category filter
    #[serde(skip_serializing_if = "Option::is_none")]
    pub category: Option<String>,
}

impl SearchRequest {
    /// Create a new search request with the given query
    #[must_use]
    pub fn new(query: impl Into<String>) -> Self {
        Self {
            query: query.into(),
            num_results: None,
            search_type: None,
            contents: None,
            include_domains: None,
            exclude_domains: None,
            start_published_date: None,
            end_published_date: None,
            livecrawl: None,
            category: None,
        }
    }

    /// Set the number of results
    #[must_use]
    pub const fn with_num_results(mut self, n: u32) -> Self {
        self.num_results = Some(n);
        self
    }

    /// Set the search type
    #[must_use]
    pub const fn with_search_type(mut self, st: SearchType) -> Self {
        self.search_type = Some(st);
        self
    }

    /// Set the contents options
    #[must_use]
    pub fn with_contents(mut self, contents: ContentsOptions) -> Self {
        self.contents = Some(contents);
        self
    }
}

/// Response from `POST /search`
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SearchResponse {
    /// Search results
    pub results: Vec<SearchResult>,

    /// Autoprompt context (orientation text generated by Exa)
    #[serde(default)]
    pub autoprompt_string: Option<String>,

    /// Cost in dollars for this request
    #[serde(default)]
    pub cost_dollars: Option<CostDollars>,

    /// Resolved search type used
    #[serde(default)]
    pub resolved_search_type: Option<String>,
}
