use crate::av_client::AvClient;
use crate::config::AppConfig;
use common_contracts::observability::TaskProgress;
use dashmap::DashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use uuid::Uuid;
use tracing::info;

#[derive(Clone, Debug)]
pub enum ServiceOperationalStatus {
    Active,
    Degraded { reason: String },
}

#[derive(Clone)]
pub struct AppState {
    pub tasks: Arc<DashMap<Uuid, TaskProgress>>,
    pub config: Arc<AppConfig>,
    pub status: Arc<RwLock<ServiceOperationalStatus>>,
    av_provider: Arc<RwLock<Option<Arc<AvClient>>>>,
}

impl AppState {
    pub fn new(config: AppConfig) -> Result<Self, anyhow::Error> {
        let initial_status = if config.alphavantage_api_key.is_some() {
            ServiceOperationalStatus::Degraded { reason: "Initializing provider, waiting for config poller to connect.".to_string() }
        } else {
            ServiceOperationalStatus::Degraded { reason: "Alphavantage API Key is not configured.".to_string() }
        };

        Ok(Self {
            tasks: Arc::new(DashMap::new()),
            config: Arc::new(config),
            status: Arc::new(RwLock::new(initial_status)),
            av_provider: Arc::new(RwLock::new(None)),
        })
    }

    pub async fn get_provider(&self) -> Option<Arc<AvClient>> {
        self.av_provider.read().await.clone()
    }

    pub async fn update_provider(&self, api_key: Option<String>, api_url: Option<String>) {
        let mut provider_guard = self.av_provider.write().await;
        let mut status_guard = self.status.write().await;

        // Fallback to default URL if not provided
        let final_url = api_url
            .filter(|s| !s.trim().is_empty())
            .or_else(|| Some("https://mcp.alphavantage.co/mcp".to_string()));

        match (api_key, final_url) {
            (Some(key), Some(base_url)) => {
                if base_url.contains('?') {
                    *provider_guard = None;
                    *status_guard = ServiceOperationalStatus::Degraded {
                        reason: "Configured MCP endpoint must not contain query parameters.".to_string(),
                    };
                    return;
                }
                let mcp_endpoint = format!("{}?apikey={}", base_url, key);
                info!("Initializing Alphavantage MCP provider with endpoint: {}", mcp_endpoint);
                match AvClient::connect(&mcp_endpoint).await {
                    Ok(new_provider) => {
                        *provider_guard = Some(Arc::new(new_provider));
                        *status_guard = ServiceOperationalStatus::Active;
                    }
                    Err(e) => {
                        *provider_guard = None;
                        *status_guard = ServiceOperationalStatus::Degraded {
                            reason: format!("Failed to connect to Alphavantage: {}", e),
                        };
                    }
                }
            }
            (None, _) => {
                *provider_guard = None;
                *status_guard = ServiceOperationalStatus::Degraded {
                    reason: "Alphavantage API Key is not configured.".to_string(),
                };
            }
            (_, None) => {
                *provider_guard = None;
                *status_guard = ServiceOperationalStatus::Degraded {
                    reason: "Alphavantage MCP endpoint is not configured.".to_string(),
                };
            }
        }
    }
}

pub type TaskStore = DashMap<Uuid, TaskProgress>;
