//! Diagnosis module for self-diagnosis guidance
//!
//! Provides structures and functions for common disease information
//! and self-diagnosis guidance.

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

/// Severity level of symptoms
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum SeverityLevel {
    Mild,
    Moderate,
    Severe,
    Emergency,
}

/// A symptom that a patient might experience
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Symptom {
    /// Symptom name
    pub name: String,
    
    /// Severity level
    pub severity: SeverityLevel,
    
    /// Duration (in days)
    pub duration_days: Option<u32>,
    
    /// Additional notes
    pub notes: Option<String>,
}

impl Symptom {
    /// Create a new symptom
    pub fn new(name: impl Into<String>, severity: SeverityLevel) -> Self {
        Self {
            name: name.into(),
            severity,
            duration_days: None,
            notes: None,
        }
    }

    /// Set duration
    pub fn with_duration(mut self, days: u32) -> Self {
        self.duration_days = Some(days);
        self
    }

    /// Set notes
    pub fn with_notes(mut self, notes: impl Into<String>) -> Self {
        self.notes = Some(notes.into());
        self
    }
}

/// Information about a disease or condition
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct DiseaseInfo {
    /// Disease name
    pub name: String,
    
    /// Alternative names
    pub alternative_names: Vec<String>,
    
    /// Description
    pub description: Option<String>,
    
    /// Common symptoms
    pub common_symptoms: Vec<String>,
    
    /// Causes
    pub causes: Vec<String>,
    
    /// Risk factors
    pub risk_factors: Vec<String>,
    
    /// Treatment options
    pub treatments: Vec<String>,
    
    /// Prevention tips
    pub prevention: Vec<String>,
    
    /// When to see a doctor
    pub when_to_see_doctor: Vec<String>,
    
    /// Source URL
    pub source_url: Option<String>,
}

impl DiseaseInfo {
    /// Create a new disease info
    pub fn new(name: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            alternative_names: Vec::new(),
            description: None,
            common_symptoms: Vec::new(),
            causes: Vec::new(),
            risk_factors: Vec::new(),
            treatments: Vec::new(),
            prevention: Vec::new(),
            when_to_see_doctor: Vec::new(),
            source_url: None,
        }
    }
}

/// Diagnosis result based on symptoms
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiagnosisResult {
    /// Possible conditions
    pub possible_conditions: Vec<PossibleCondition>,
    
    /// General recommendations
    pub recommendations: Vec<String>,
    
    /// Whether immediate medical attention is needed
    pub needs_immediate_attention: bool,
}

/// A possible condition with confidence score
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PossibleCondition {
    /// Disease information
    pub disease: DiseaseInfo,
    
    /// Confidence score (0.0 to 1.0)
    pub confidence: f32,
    
    /// Matching symptoms
    pub matching_symptoms: Vec<String>,
}

/// Service for disease diagnosis
pub struct DiagnosisService {
    client: HHClient,
}

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

    /// Analyze symptoms and provide possible diagnoses
    pub async fn analyze_symptoms(&self, symptoms: &[Symptom]) -> Result<DiagnosisResult> {
        // Check if any symptom is severe or emergency
        let needs_immediate_attention = symptoms
            .iter()
            .any(|s| matches!(s.severity, SeverityLevel::Severe | SeverityLevel::Emergency));

        // This is a placeholder implementation
        // In a real implementation:
        // 1. Analyze symptom patterns
        // 2. Match against disease databases
        // 3. Calculate confidence scores
        // 4. Provide ranked possible conditions

        let recommendations = if needs_immediate_attention {
            vec![
                "Seek immediate medical attention".to_string(),
                "Call emergency services if symptoms worsen".to_string(),
            ]
        } else {
            vec![
                "Monitor your symptoms".to_string(),
                "Consult with a healthcare provider if symptoms persist".to_string(),
                "Stay hydrated and get adequate rest".to_string(),
            ]
        };

        Ok(DiagnosisResult {
            possible_conditions: Vec::new(),
            recommendations,
            needs_immediate_attention,
        })
    }

    /// Get information about a specific disease
    pub async fn get_disease_info(&self, disease_name: &str) -> Result<DiseaseInfo> {
        let _html = self.client.fetch_html(&format!(
            "https://example.com/diseases/{}",
            disease_name
        )).await?;

        // TODO: Parse HTML and extract disease information
        
        Ok(DiseaseInfo::new(disease_name))
    }

    /// Search for diseases by symptoms
    pub async fn search_by_symptoms(&self, symptom_names: &[String]) -> Result<Vec<DiseaseInfo>> {
        // This is a placeholder
        // In reality, you would:
        // 1. Query medical databases or APIs
        // 2. Match symptoms to diseases
        // 3. Return ranked results
        
        let _ = symptom_names;
        Ok(Vec::new())
    }
}

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

    #[test]
    fn test_symptom_creation() {
        let symptom = Symptom::new("Headache", SeverityLevel::Mild)
            .with_duration(2)
            .with_notes("Starts in the morning");

        assert_eq!(symptom.name, "Headache");
        assert_eq!(symptom.severity, SeverityLevel::Mild);
        assert_eq!(symptom.duration_days, Some(2));
    }

    #[tokio::test]
    async fn test_diagnosis_service() {
        let client = HHClient::new();
        let service = DiagnosisService::new(client);
        
        let symptoms = vec![
            Symptom::new("Fever", SeverityLevel::Moderate),
            Symptom::new("Cough", SeverityLevel::Mild),
        ];
        
        let result = service.analyze_symptoms(&symptoms).await;
        assert!(result.is_ok());
    }

    #[tokio::test]
    async fn test_emergency_detection() {
        let client = HHClient::new();
        let service = DiagnosisService::new(client);
        
        let symptoms = vec![
            Symptom::new("Chest pain", SeverityLevel::Severe),
        ];
        
        let result = service.analyze_symptoms(&symptoms).await.unwrap();
        assert!(result.needs_immediate_attention);
    }
}
