use rouille::{input::json_input, Request, Response};
use serde_json::json;
use std::sync::Arc;

use super::helpers::{get_conn, json_error, require_auth};
use super::AppState;

// ==================== Plesk Servers ====================

pub fn list_plesk(request: &Request, state: &Arc<AppState>) -> Response {
    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    match conn.query(
        "SELECT id, name, host, port, connection_status, is_active \
         FROM plesk_servers ORDER BY name",
        &[],
    ) {
        Ok(rows) => {
            let servers: Vec<_> = rows
                .into_iter()
                .map(|row| {
                    json!({
                        "id": row.get::<_, i32>(0),
                        "name": row.get::<_, String>(1),
                        "host": row.get::<_, String>(2),
                        "port": row.get::<_, i32>(3),
                        "connection_status": row.get::<_, String>(4),
                        "is_active": row.get::<_, bool>(5),
                    })
                })
                .collect();
            Response::json(&servers)
        }
        Err(_) => json_error(500, "Database error"),
    }
}

pub fn create_plesk(request: &Request, state: &Arc<AppState>) -> Response {
    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    let data: serde_json::Value = match json_input(request) {
        Ok(f) => f,
        Err(_) => return json_error(400, "Invalid JSON"),
    };

    let name = str_field(&data, "name");
    let host = str_field(&data, "host");
    if name.is_empty() || host.is_empty() {
        return json_error(400, "Name and host are required");
    }

    let port = data.get("port").and_then(|v| v.as_i64()).unwrap_or(8443) as i32;
    let api_key = str_field(&data, "api_key");
    let username = str_field(&data, "username");
    let password = str_field(&data, "password");
    let use_https = data.get("use_https").and_then(|v| v.as_bool()).unwrap_or(true);
    let verify_ssl = data.get("verify_ssl").and_then(|v| v.as_bool()).unwrap_or(true);

    match conn.query_one(
        "INSERT INTO plesk_servers (name, host, port, api_key, username, password_hash, \
         use_https, verify_ssl, connection_status, is_active, created_at) \
         VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 'unknown', true, NOW()) RETURNING id",
        &[&name, &host, &port, &api_key, &username, &password, &use_https, &verify_ssl],
    ) {
        Ok(r) => Response::json(&json!({
            "id": r.get::<_, i32>(0), "name": name, "host": host, "port": port,
            "message": "Plesk server created successfully"
        })),
        Err(e) => {
            log::error!("Database error: {}", e);
            json_error(500, "Failed to create server")
        }
    }
}

pub fn get_plesk(request: &Request, state: &Arc<AppState>, id: &str) -> Response {
    let server_id = parse_id(id);
    if server_id == 0 {
        return json_error(400, "Invalid server ID");
    }

    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    match conn.query_opt(
        "SELECT id, name, host, port, connection_status, is_active \
         FROM plesk_servers WHERE id = $1",
        &[&server_id],
    ) {
        Ok(Some(row)) => Response::json(&json!({
            "id": row.get::<_, i32>(0), "name": row.get::<_, String>(1),
            "host": row.get::<_, String>(2), "port": row.get::<_, i32>(3),
            "connection_status": row.get::<_, String>(4), "is_active": row.get::<_, bool>(5),
        })),
        Ok(None) => json_error(404, "Server not found"),
        Err(_) => json_error(500, "Database error"),
    }
}

pub fn update_plesk(request: &Request, state: &Arc<AppState>, id: &str) -> Response {
    let server_id = parse_id(id);
    if server_id == 0 {
        return json_error(400, "Invalid server ID");
    }

    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    let data: serde_json::Value = match json_input(request) {
        Ok(f) => f,
        Err(_) => return json_error(400, "Invalid JSON"),
    };

    let name = str_field(&data, "name");
    let host = str_field(&data, "host");
    let port = data.get("port").and_then(|v| v.as_i64()).unwrap_or(8443) as i32;
    let api_key = str_field(&data, "api_key");
    let username = str_field(&data, "username");
    let password = str_field(&data, "password");
    let use_https = data.get("use_https").and_then(|v| v.as_bool()).unwrap_or(true);
    let verify_ssl = data.get("verify_ssl").and_then(|v| v.as_bool()).unwrap_or(true);

    match conn.execute(
        "UPDATE plesk_servers SET name=$1, host=$2, port=$3, api_key=$4, username=$5, \
         password_hash=$6, use_https=$7, verify_ssl=$8, updated_at=NOW() WHERE id=$9",
        &[&name, &host, &port, &api_key, &username, &password, &use_https, &verify_ssl, &server_id],
    ) {
        Ok(_) => Response::json(&json!({"message": "Server updated successfully"})),
        Err(e) => {
            log::error!("Database error: {}", e);
            json_error(500, "Failed to update server")
        }
    }
}

pub fn delete_plesk(request: &Request, state: &Arc<AppState>, id: &str) -> Response {
    let server_id = parse_id(id);
    if server_id == 0 {
        return json_error(400, "Invalid server ID");
    }

    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    match conn.execute("DELETE FROM plesk_servers WHERE id = $1", &[&server_id]) {
        Ok(_) => Response::json(&json!({"message": "Server deleted successfully"})),
        Err(e) => {
            log::error!("Database error: {}", e);
            json_error(500, "Failed to delete server")
        }
    }
}

pub fn test_plesk(request: &Request, state: &Arc<AppState>, id: &str) -> Response {
    let server_id = parse_id(id);
    if server_id == 0 {
        return json_error(400, "Invalid server ID");
    }

    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    let config = match conn.query_opt(
        "SELECT host, port, api_key, username, password_hash, use_https, verify_ssl \
         FROM plesk_servers WHERE id = $1",
        &[&server_id],
    ) {
        Ok(Some(row)) => sap_sync_backend::models::PleskConfig {
            host: row.get(0),
            port: row.get::<_, i32>(1) as u16,
            api_key: row.get(2),
            username: row.get(3),
            password: row.get(4),
            use_https: row.get(5),
            verify_ssl: row.get(6),
            two_factor_enabled: false,
            two_factor_method: "none".to_string(),
            two_factor_secret: None,
            session_id: None,
        },
        Ok(None) => return json_error(404, "Server not found"),
        Err(_) => return json_error(500, "Database error"),
    };

    let result = sap_sync_backend::plesk_client::test_plesk_connection(&config, None, Some(10));

    let status = if result.success { "connected" } else { "disconnected" };
    let _ = conn.execute(
        "UPDATE plesk_servers SET connection_status = $1, \
         last_connected = CASE WHEN $1 = 'connected' THEN NOW() ELSE last_connected END \
         WHERE id = $2",
        &[&status, &server_id],
    );

    Response::json(&json!({
        "success": result.success, "message": result.message,
        "latency_ms": result.latency_ms, "error": result.error,
        "requires_2fa": result.requires_2fa, "session_id": result.session_id,
        "two_factor_method": result.two_factor_method,
    }))
}

// ==================== SAP Servers ====================

pub fn list_sap(request: &Request, state: &Arc<AppState>) -> Response {
    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    match conn.query(
        "SELECT id, name, host, port, company_db, connection_status, is_active \
         FROM sap_servers ORDER BY name",
        &[],
    ) {
        Ok(rows) => {
            let servers: Vec<_> = rows
                .into_iter()
                .map(|row| {
                    json!({
                        "id": row.get::<_, i32>(0),
                        "name": row.get::<_, String>(1),
                        "host": row.get::<_, String>(2),
                        "port": row.get::<_, i32>(3),
                        "company_db": row.get::<_, String>(4),
                        "connection_status": row.get::<_, String>(5),
                        "is_active": row.get::<_, bool>(6),
                    })
                })
                .collect();
            Response::json(&servers)
        }
        Err(_) => json_error(500, "Database error"),
    }
}

pub fn create_sap(request: &Request, state: &Arc<AppState>) -> Response {
    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    let data: serde_json::Value = match json_input(request) {
        Ok(f) => f,
        Err(_) => return json_error(400, "Invalid JSON"),
    };

    let name = str_field(&data, "name");
    let host = str_field(&data, "host");
    let company_db = str_field(&data, "company_db");
    if name.is_empty() || host.is_empty() || company_db.is_empty() {
        return json_error(400, "Name, host, and company database are required");
    }

    let port = data.get("port").and_then(|v| v.as_i64()).unwrap_or(50000) as i32;
    let username = str_field(&data, "username");
    let password = str_field(&data, "password");
    let use_ssl = data.get("use_ssl").and_then(|v| v.as_bool()).unwrap_or(true);

    match conn.query_one(
        "INSERT INTO sap_servers (name, host, port, company_db, username, password_hash, \
         use_ssl, connection_status, is_active, created_at) \
         VALUES ($1, $2, $3, $4, $5, $6, $7, 'unknown', true, NOW()) RETURNING id",
        &[&name, &host, &port, &company_db, &username, &password, &use_ssl],
    ) {
        Ok(r) => Response::json(&json!({
            "id": r.get::<_, i32>(0), "name": name, "host": host,
            "port": port, "company_db": company_db,
            "message": "SAP server created successfully"
        })),
        Err(e) => {
            log::error!("Database error: {}", e);
            json_error(500, "Failed to create server")
        }
    }
}

pub fn get_sap(request: &Request, state: &Arc<AppState>, id: &str) -> Response {
    let server_id = parse_id(id);
    if server_id == 0 {
        return json_error(400, "Invalid server ID");
    }

    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    match conn.query_opt(
        "SELECT id, name, host, port, company_db, connection_status, is_active \
         FROM sap_servers WHERE id = $1",
        &[&server_id],
    ) {
        Ok(Some(row)) => Response::json(&json!({
            "id": row.get::<_, i32>(0), "name": row.get::<_, String>(1),
            "host": row.get::<_, String>(2), "port": row.get::<_, i32>(3),
            "company_db": row.get::<_, String>(4),
            "connection_status": row.get::<_, String>(5), "is_active": row.get::<_, bool>(6),
        })),
        Ok(None) => json_error(404, "Server not found"),
        Err(_) => json_error(500, "Database error"),
    }
}

pub fn update_sap(request: &Request, state: &Arc<AppState>, id: &str) -> Response {
    let server_id = parse_id(id);
    if server_id == 0 {
        return json_error(400, "Invalid server ID");
    }

    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    let data: serde_json::Value = match json_input(request) {
        Ok(f) => f,
        Err(_) => return json_error(400, "Invalid JSON"),
    };

    let name = str_field(&data, "name");
    let host = str_field(&data, "host");
    let port = data.get("port").and_then(|v| v.as_i64()).unwrap_or(50000) as i32;
    let company_db = str_field(&data, "company_db");
    let username = str_field(&data, "username");
    let password = str_field(&data, "password");
    let use_ssl = data.get("use_ssl").and_then(|v| v.as_bool()).unwrap_or(true);

    match conn.execute(
        "UPDATE sap_servers SET name=$1, host=$2, port=$3, company_db=$4, username=$5, \
         password_hash=$6, use_ssl=$7, updated_at=NOW() WHERE id=$8",
        &[&name, &host, &port, &company_db, &username, &password, &use_ssl, &server_id],
    ) {
        Ok(_) => Response::json(&json!({"message": "Server updated successfully"})),
        Err(e) => {
            log::error!("Database error: {}", e);
            json_error(500, "Failed to update server")
        }
    }
}

pub fn delete_sap(request: &Request, state: &Arc<AppState>, id: &str) -> Response {
    let server_id = parse_id(id);
    if server_id == 0 {
        return json_error(400, "Invalid server ID");
    }

    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    match conn.execute("DELETE FROM sap_servers WHERE id = $1", &[&server_id]) {
        Ok(_) => Response::json(&json!({"message": "Server deleted successfully"})),
        Err(e) => {
            log::error!("Database error: {}", e);
            json_error(500, "Failed to delete server")
        }
    }
}

pub fn test_sap(request: &Request, state: &Arc<AppState>, id: &str) -> Response {
    let server_id = parse_id(id);
    if server_id == 0 {
        return json_error(400, "Invalid server ID");
    }

    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    let config = match conn.query_opt(
        "SELECT host, port, company_db, username, password_hash, use_ssl \
         FROM sap_servers WHERE id = $1",
        &[&server_id],
    ) {
        Ok(Some(row)) => sap_sync_backend::models::SapConfig {
            host: row.get(0),
            port: row.get::<_, i32>(1) as u16,
            company_db: row.get(2),
            username: row.get(3),
            password: row.get(4),
            use_ssl: row.get(5),
            timeout_seconds: 30,
        },
        Ok(None) => return json_error(404, "Server not found"),
        Err(_) => return json_error(500, "Database error"),
    };

    let result = sap_sync_backend::sap_client::test_sap_connection(&config, Some(10));

    let status = if result.success { "connected" } else { "disconnected" };
    let _ = conn.execute(
        "UPDATE sap_servers SET connection_status = $1, \
         last_connected = CASE WHEN $1 = 'connected' THEN NOW() ELSE last_connected END \
         WHERE id = $2",
        &[&status, &server_id],
    );

    Response::json(&json!({
        "success": result.success, "message": result.message,
        "latency_ms": result.latency_ms, "error": result.error,
        "session_id": result.session_id,
    }))
}

// ==================== Direct Test (without saved server) ====================

pub fn test_sap_direct(request: &Request, state: &Arc<AppState>) -> Response {
    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    let config: sap_sync_backend::models::SapConfig = match json_input(request) {
        Ok(f) => f,
        Err(_) => return json_error(400, "Invalid JSON"),
    };

    let result = sap_sync_backend::sap_client::test_sap_connection(&config, Some(10));
    Response::json(&json!({
        "success": result.success, "message": result.message,
        "latency_ms": result.latency_ms, "error": result.error,
        "session_id": result.session_id,
    }))
}

pub fn test_plesk_direct(request: &Request, state: &Arc<AppState>) -> Response {
    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    let config: sap_sync_backend::models::PleskConfig = match json_input(request) {
        Ok(f) => f,
        Err(_) => return json_error(400, "Invalid JSON"),
    };

    let result = sap_sync_backend::plesk_client::test_plesk_connection(&config, None, Some(10));
    Response::json(&json!({
        "success": result.success, "message": result.message,
        "latency_ms": result.latency_ms, "error": result.error,
        "requires_2fa": result.requires_2fa, "session_id": result.session_id,
        "two_factor_method": result.two_factor_method,
    }))
}

// ==================== Helpers ====================

fn parse_id(id: &str) -> i32 {
    id.parse::<i32>().unwrap_or(0)
}

fn str_field(data: &serde_json::Value, key: &str) -> String {
    data.get(key)
        .and_then(|v| v.as_str())
        .unwrap_or_default()
        .to_string()
}
