use common_contracts::observability::TaskProgress;
use std::sync::Arc;
use tokio::sync::RwLock;

use crate::config::AppConfig;
use crate::finnhub::FinnhubDataProvider;
use dashmap::DashMap;
use uuid::Uuid;

#[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>>,
    finnhub_provider: Arc<RwLock<Option<FinnhubDataProvider>>>,
}

impl AppState {
    pub fn new(config: AppConfig) -> Self {
        let (initial_provider, initial_status) =
            if let Some(api_key) = config.finnhub_api_key.as_ref() {
                let provider = FinnhubDataProvider::new(
                    config.finnhub_api_url.clone(),
                    api_key.to_string(),
                );
                (Some(provider), ServiceOperationalStatus::Active)
            } else {
                (
                    None,
                    ServiceOperationalStatus::Degraded {
                        reason: "Finnhub API Key is not configured.".to_string(),
                    },
                )
            };

        Self {
            tasks: Arc::new(DashMap::new()),
            config: Arc::new(config),
            status: Arc::new(RwLock::new(initial_status)),
            finnhub_provider: Arc::new(RwLock::new(initial_provider)),
        }
    }

    pub async fn get_provider(&self) -> Option<FinnhubDataProvider> {
        self.finnhub_provider.read().await.clone()
    }

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

        let final_url = api_url
            .filter(|s| !s.trim().is_empty())
            .unwrap_or_else(|| "https://finnhub.io/api/v1".to_string());

        if let Some(key) = api_key {
            let new_provider = FinnhubDataProvider::new(
                final_url,
                key,
            );
            *provider_guard = Some(new_provider);
            *status_guard = ServiceOperationalStatus::Active;
        } else {
            *provider_guard = None;
            *status_guard = ServiceOperationalStatus::Degraded {
                reason: "Finnhub API Key is not configured.".to_string(),
            };
        }
    }
}
