use crate::error::Result;
use crate::state::{AppState, ServiceOperationalStatus};
use common_contracts::messages::FetchCompanyDataCommand;
use common_contracts::subjects::NatsSubject;
use futures_util::StreamExt;
use std::time::Duration;
use tracing::{error, info, warn};

pub async fn run(state: AppState) -> Result<()> {
    info!("Starting NATS message consumer...");

    loop {
        let status = state.status.read().await.clone();
        if let ServiceOperationalStatus::Degraded { reason } = status {
            warn!(
                "Service is in degraded state (reason: {}). Pausing message consumption for 30s.",
                reason
            );
            tokio::time::sleep(Duration::from_secs(30)).await;
            continue;
        }

        info!("Service is Active. Connecting to NATS...");
        match async_nats::connect(&state.config.nats_addr).await {
            Ok(client) => {
                info!("Successfully connected to NATS.");
                if let Err(e) = subscribe_and_process(state.clone(), client).await {
                    error!("NATS subscription error: {}. Reconnecting in 10s...", e);
                }
            }
            Err(e) => {
                error!("Failed to connect to NATS: {}. Retrying in 10s...", e);
            }
        }
        tokio::time::sleep(Duration::from_secs(10)).await;
    }
}

async fn subscribe_and_process(state: AppState, client: async_nats::Client) -> Result<()> {
    let subject = NatsSubject::DataFetchCommands.to_string();
    let mut subscriber = client.subscribe(subject.clone()).await?;
    info!(
        "Consumer started, waiting for messages on subject '{}'",
        subject
    );

    while let Some(message) = subscriber.next().await {
        let current_status = state.status.read().await.clone();
        if matches!(current_status, ServiceOperationalStatus::Degraded {..}) {
            warn!("Service became degraded. Disconnecting from NATS and pausing consumption.");
            subscriber.unsubscribe().await?;
            return Ok(());
        }

        info!("Received NATS message.");
        let state_clone = state.clone();
        let publisher_clone = client.clone();

        tokio::spawn(async move {
            match serde_json::from_slice::<FetchCompanyDataCommand>(&message.payload) {
                Ok(command) => {
                    let request_id = command.request_id;
                    info!("Deserialized command for symbol: {}", command.symbol);
                    if let Err(e) =
                        crate::worker::handle_fetch_command(state_clone.clone(), command, publisher_clone)
                            .await
                    {
                        error!("Error handling fetch command: {:?}", e);
                        if let Some(mut task) = state_clone.tasks.get_mut(&request_id) {
                            task.status = common_contracts::observability::ObservabilityTaskStatus::Failed;
                            task.details = format!("Worker failed: {}", e);
                        }
                    }
                }
                Err(e) => {
                    error!("Failed to deserialize message: {}", e);
                }
            }
        });
    }
    Ok(())
}
