use crate::error::{AppError, AppResult};
use serde::{Deserialize, Serialize};
use std::fs;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use tiny_http::{Response, Server};

static SERVER_RUNNING: AtomicBool = AtomicBool::new(false);

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalServerInfo {
    pub url: String,
    pub qr_payload: String,
}

#[tauri::command]
pub fn start_local_profile_server(profile_path: String) -> AppResult<LocalServerInfo> {
    if SERVER_RUNNING.load(Ordering::SeqCst) {
        return Err(AppError::new("Local server is already running"));
    }

    let path = PathBuf::from(profile_path);
    if !path.exists() {
        return Err(AppError::new(format!(
            "Profile not found at {}",
            path.display()
        )));
    }

    // Try to bind to a port; fall back if 8123 is taken
    let port = find_free_port(8123)?;
    let addr: SocketAddr = format!("0.0.0.0:{}", port).parse().map_err(|e| {
        AppError::new(format!("Failed to parse socket address: {}", e))
    })?;

    let server = Server::http(addr).map_err(|e| {
        AppError::new(format!("Failed to start local HTTP server: {}", e))
    })?;

    let local_ip = local_ip_address::local_ip().ok();
    let host = local_ip
        .map(|ip| ip.to_string())
        .unwrap_or_else(|| "localhost".to_string());

    let url = format!("http://{}:{}/profile.mobileconfig", host, port);
    let qr_payload = url.clone();
    let profile_bytes = fs::read(&path)?;

    SERVER_RUNNING.store(true, Ordering::SeqCst);

    thread::spawn(move || {
        for request in server.incoming_requests() {
            let response = Response::from_data(profile_bytes.clone())
                .with_header(
                    tiny_http::Header::from_bytes(
                        &b"Content-Type"[..],
                        &b"application/x-apple-aspen-config"[..],
                    )
                    .unwrap(),
                );
            let _ = request.respond(response);
        }
        SERVER_RUNNING.store(false, Ordering::SeqCst);
    });

    Ok(LocalServerInfo { url, qr_payload })
}

#[tauri::command]
pub fn stop_local_profile_server() -> AppResult<()> {
    // tiny_http does not support graceful shutdown out of the box.
    // In a real implementation, store the server handle and close it.
    SERVER_RUNNING.store(false, Ordering::SeqCst);
    Ok(())
}

fn find_free_port(start: u16) -> AppResult<u16> {
    for port in start..start + 100 {
        match std::net::TcpListener::bind(format!("0.0.0.0:{}", port)) {
            Ok(_) => return Ok(port),
            Err(_) => continue,
        }
    }
    Err(AppError::new("No free port found in range 8123-8222"))
}
