use crate::config::AppConfig;
use crate::tushare::TushareDataProvider;
use common_contracts::observability::{TaskProgress, ObservabilityTaskStatus};
use common_contracts::workflow_harness::TaskState;
use dashmap::DashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use uuid::Uuid;
use secrecy::SecretString;

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

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

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

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

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

        // Default Tushare URL if not provided or empty
        let final_url = api_url
            .filter(|s| !s.trim().is_empty())
            .unwrap_or_else(|| "http://api.tushare.pro".to_string());

        if let Some(key) = api_key {
            use secrecy::ExposeSecret;
            let new_provider = TushareDataProvider::new(
                final_url,
                key.expose_secret().clone(),
            );
            *provider_guard = Some(new_provider);
            *status_guard = ServiceOperationalStatus::Active;
        } else {
            *provider_guard = None;
            *status_guard = ServiceOperationalStatus::Degraded {
                reason: "Tushare API Key is not configured.".to_string(),
            };
        }
    }
}

// Implement TaskState trait for AppState
#[async_trait::async_trait]
impl TaskState for AppState {
    fn update_status(&self, task_id: Uuid, status: ObservabilityTaskStatus, progress: u8, details: String) {
        if let Some(mut task) = self.tasks.get_mut(&task_id) {
            task.status = status;
            task.progress_percent = progress;
            task.details = details;
        }
    }

    fn fail_task(&self, task_id: Uuid, error: String) {
        if let Some(mut task) = self.tasks.get_mut(&task_id) {
            task.status = ObservabilityTaskStatus::Failed;
            task.details = format!("Failed: {}", error);
        }
    }

    fn complete_task(&self, task_id: Uuid, details: String) {
        if let Some(mut task) = self.tasks.get_mut(&task_id) {
            task.status = ObservabilityTaskStatus::Completed;
            task.progress_percent = 100;
            task.details = details;
        }
    }

    fn get_nats_addr(&self) -> String {
        self.config.nats_addr.clone()
    }

    fn get_persistence_url(&self) -> String {
        self.config.data_persistence_service_url.clone()
    }
}
