use crate::error::{TuskError, TuskResult};
use crate::mcp;
use crate::models::settings::{AppSettings, McpStatus};
use crate::state::AppState;
use std::fs;
use std::sync::Arc;
use tauri::{AppHandle, Manager, State};

fn get_settings_path(app: &AppHandle) -> TuskResult<std::path::PathBuf> {
    let dir = app
        .path()
        .app_data_dir()
        .map_err(|e| TuskError::Config(e.to_string()))?;
    fs::create_dir_all(&dir)?;
    Ok(dir.join("app_settings.json"))
}

#[tauri::command]
pub async fn get_app_settings(app: AppHandle) -> TuskResult<AppSettings> {
    let path = get_settings_path(&app)?;
    if !path.exists() {
        return Ok(AppSettings::default());
    }
    let data = fs::read_to_string(&path)?;
    let settings: AppSettings = serde_json::from_str(&data)?;
    Ok(settings)
}

#[tauri::command]
pub async fn save_app_settings(
    app: AppHandle,
    state: State<'_, Arc<AppState>>,
    settings: AppSettings,
) -> TuskResult<()> {
    let path = get_settings_path(&app)?;
    let data = serde_json::to_string_pretty(&settings)?;
    fs::write(&path, data)?;

    // Apply MCP setting: restart or stop
    let is_running = *state.mcp_running.read().await;

    if settings.mcp.enabled {
        if is_running {
            // Stop existing MCP server first
            let _ = state.mcp_shutdown_tx.send(true);
            // Give it a moment to shut down
            tokio::time::sleep(std::time::Duration::from_millis(200)).await;
            *state.mcp_running.write().await = false;
        }

        // Start new MCP server
        let connections_path = app
            .path()
            .app_data_dir()
            .map_err(|e| TuskError::Config(e.to_string()))?
            .join("connections.json");

        let mcp_state = state.inner().clone();
        let port = settings.mcp.port;
        let shutdown_rx = state.mcp_shutdown_tx.subscribe();

        tokio::spawn(async move {
            *mcp_state.mcp_running.write().await = true;
            if let Err(e) =
                mcp::start_mcp_server(mcp_state.clone(), connections_path, port, shutdown_rx).await
            {
                log::error!("MCP server error: {}", e);
            }
            *mcp_state.mcp_running.write().await = false;
        });
    } else if is_running {
        // Stop MCP server
        let _ = state.mcp_shutdown_tx.send(true);
        *state.mcp_running.write().await = false;
    }

    Ok(())
}

#[tauri::command]
pub async fn get_mcp_status(app: AppHandle) -> TuskResult<McpStatus> {
    // Read settings from file for enabled/port
    let settings = {
        let path = get_settings_path(&app)?;
        if path.exists() {
            let data = fs::read_to_string(&path)?;
            serde_json::from_str::<AppSettings>(&data).unwrap_or_default()
        } else {
            AppSettings::default()
        }
    };

    // Probe the actual port to determine if MCP is running
    let running = tokio::time::timeout(
        std::time::Duration::from_millis(500),
        tokio::net::TcpStream::connect(format!("127.0.0.1:{}", settings.mcp.port)),
    )
    .await
    .map(|r| r.is_ok())
    .unwrap_or(false);

    Ok(McpStatus {
        enabled: settings.mcp.enabled,
        port: settings.mcp.port,
        running,
    })
}
