// src/monitoring/webserver.rs
use super::service::MonitoringService;
use axum::{
    extract::{
        ws::{Message, WebSocket, WebSocketUpgrade},
        State,
    },
    response::{Html, IntoResponse, Response},
    routing::get,
    Router,
};
use std::sync::Arc;
use tokio::sync::RwLock;
use tokio::time::{interval, Duration};

const UPDATE_INTERVAL_MS: u64 = 1000; // 1 second updates

pub struct WebServer {
    service: Arc<RwLock<MonitoringService>>,
    port: u16,
}

impl WebServer {
    pub fn new(service: Arc<RwLock<MonitoringService>>, port: u16) -> Self {
        Self { service, port }
    }

    pub async fn run(self) -> anyhow::Result<()> {
        let app = Router::new()
            .route("/", get(dashboard_handler))
            .route("/ws", get(websocket_handler))
            .with_state(self.service);

        let addr = format!("0.0.0.0:{}", self.port);
        println!("📊 Dashboard available at: http://localhost:{}", self.port);

        let listener = tokio::net::TcpListener::bind(&addr).await?;
        axum::serve(listener, app).await?;

        Ok(())
    }
}

async fn dashboard_handler() -> impl IntoResponse {
    Html(include_str!("dashboard.html"))
}

async fn websocket_handler(
    ws: WebSocketUpgrade,
    State(service): State<Arc<RwLock<MonitoringService>>>,
) -> Response {
    ws.on_upgrade(|socket| handle_socket(socket, service))
}

async fn handle_socket(mut socket: WebSocket, service: Arc<RwLock<MonitoringService>>) {
    let mut ticker = interval(Duration::from_millis(UPDATE_INTERVAL_MS));

    loop {
        ticker.tick().await;

        let service_guard = service.read().await;
        let state = service_guard.get_dashboard_state().await;
        drop(service_guard);

        match serde_json::to_string(&state) {
            Ok(json) => {
                if socket.send(Message::Text(json)).await.is_err() {
                    break; // Client disconnected
                }
            }
            Err(e) => {
                eprintln!("Failed to serialize dashboard state: {}", e);
                break;
            }
        }
    }
}