//! Medicine information module
//!
//! Provides structures and functions for fetching drug information
//! from pharmaceutical company websites.

use crate::client::HHClient;
use crate::error::{HHError, Result};
use serde::{Deserialize, Serialize};

/// Information about a medicine/drug
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct MedicineInfo {
    /// Drug name
    pub name: String,
    
    /// Generic name (scientific name)
    pub generic_name: Option<String>,
    
    /// Drug manufacturer
    pub manufacturer: Option<String>,
    
    /// Drug description
    pub description: Option<String>,
    
    /// Indications (what it's used for)
    pub indications: Vec<String>,
    
    /// Dosage information
    pub dosage: Option<String>,
    
    /// Side effects
    pub side_effects: Vec<String>,
    
    /// Contraindications (when not to use)
    pub contraindications: Vec<String>,
    
    /// Warnings and precautions
    pub warnings: Vec<String>,
    
    /// Source URL
    pub source_url: Option<String>,
}

impl MedicineInfo {
    /// Create a new MedicineInfo with required fields
    pub fn new(name: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            generic_name: None,
            manufacturer: None,
            description: None,
            indications: Vec::new(),
            dosage: None,
            side_effects: Vec::new(),
            contraindications: Vec::new(),
            warnings: Vec::new(),
            source_url: None,
        }
    }

    /// Builder pattern: set generic name
    pub fn with_generic_name(mut self, name: impl Into<String>) -> Self {
        self.generic_name = Some(name.into());
        self
    }

    /// Builder pattern: set manufacturer
    pub fn with_manufacturer(mut self, manufacturer: impl Into<String>) -> Self {
        self.manufacturer = Some(manufacturer.into());
        self
    }

    /// Builder pattern: set description
    pub fn with_description(mut self, description: impl Into<String>) -> Self {
        self.description = Some(description.into());
        self
    }

    /// Builder pattern: set source URL
    pub fn with_source_url(mut self, url: impl Into<String>) -> Self {
        self.source_url = Some(url.into());
        self
    }
}

/// Medicine search query parameters
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MedicineQuery {
    /// Search term (drug name or generic name)
    pub query: String,
    
    /// Optional manufacturer filter
    pub manufacturer: Option<String>,
    
    /// Maximum number of results
    pub limit: Option<usize>,
}

impl MedicineQuery {
    /// Create a new medicine query
    pub fn new(query: impl Into<String>) -> Self {
        Self {
            query: query.into(),
            manufacturer: None,
            limit: Some(10),
        }
    }
}

/// Medicine service for fetching drug information
pub struct MedicineService {
    client: HHClient,
}

impl MedicineService {
    /// Create a new medicine service
    pub fn new(client: HHClient) -> Self {
        Self { client }
    }

    /// Search for medicines by name
    pub async fn search(&self, query: &MedicineQuery) -> Result<Vec<MedicineInfo>> {
        // This is a placeholder implementation
        // In a real implementation, you would:
        // 1. Use the client to fetch data from pharmaceutical websites
        // 2. Parse the HTML response
        // 3. Extract medicine information
        // 4. Return structured data
        
        // For now, return mock data
        Ok(vec![
            MedicineInfo::new(&query.query)
                .with_description("This is a placeholder. Implement scraping logic for actual data."),
        ])
    }

    /// Get detailed information about a specific medicine
    pub async fn get_details(&self, medicine_name: &str) -> Result<MedicineInfo> {
        let query = MedicineQuery::new(medicine_name);
        let results = self.search(&query).await?;
        
        results
            .into_iter()
            .next()
            .ok_or_else(|| HHError::NotFound(format!("Medicine '{}' not found", medicine_name)))
    }

    /// Get medicine information from a specific URL
    /// This is useful when you know the exact URL of a drug information page
    pub async fn fetch_from_url(&self, url: &str) -> Result<MedicineInfo> {
        let _html = self.client.fetch_html(url).await?;
        
        // TODO: Implement HTML parsing logic here
        // Use scraper or select crate to extract information
        
        Ok(MedicineInfo::new("Example Drug")
            .with_source_url(url)
            .with_description("Implement parsing logic to extract actual data"))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_medicine_info_builder() {
        let medicine = MedicineInfo::new("Aspirin")
            .with_generic_name("Acetylsalicylic acid")
            .with_manufacturer("Bayer")
            .with_description("Pain reliever and fever reducer");

        assert_eq!(medicine.name, "Aspirin");
        assert_eq!(medicine.generic_name, Some("Acetylsalicylic acid".to_string()));
        assert_eq!(medicine.manufacturer, Some("Bayer".to_string()));
    }

    #[tokio::test]
    async fn test_medicine_service() {
        let client = HHClient::new();
        let service = MedicineService::new(client);
        let query = MedicineQuery::new("test");
        
        let results = service.search(&query).await;
        assert!(results.is_ok());
    }
}
