use serde_json::{json, Value};
use wasm_bindgen::prelude::*;

#[wasm_bindgen(js_name = compareVersions)]
pub fn compare_versions(a: &str, b: &str) -> i32 {
    let mut av = parse_version(a);
    let mut bv = parse_version(b);
    av.resize(4, 0);
    bv.resize(4, 0);
    for index in 0..4 {
        if av[index] > bv[index] {
            return 1;
        }
        if av[index] < bv[index] {
            return -1;
        }
    }
    0
}

#[wasm_bindgen(js_name = scoreEndpointHealth)]
pub fn score_endpoint_health(status: &str, latency_ms: i32, failures: i32) -> i32 {
    let base = match status {
        "ok" => 100,
        "degraded" => 70,
        "error" => 30,
        _ => 50,
    };
    let latency_penalty = (latency_ms / 250).clamp(0, 30);
    let failure_penalty = (failures * 12).clamp(0, 48);
    (base - latency_penalty - failure_penalty).clamp(0, 100)
}

#[wasm_bindgen(js_name = normalizeReleaseManifest)]
pub fn normalize_release_manifest(input: &str) -> String {
    let mut value: Value = serde_json::from_str(input).unwrap_or_else(|_| json!({}));
    if value.get("manifest_version").is_none() {
        value["manifest_version"] = json!(2);
    }
    if value.get("packages").is_none() {
        value["packages"] = json!([]);
    }
    serde_json::to_string(&value).unwrap_or_else(|_| "{}".to_string())
}

#[wasm_bindgen(js_name = validateSourceCatalog)]
pub fn validate_source_catalog(input: &str) -> String {
    let value: Value = serde_json::from_str(input).unwrap_or_else(|_| json!({}));
    let categories = value
        .get("categories")
        .and_then(|item| item.as_array())
        .map(|items| items.len())
        .unwrap_or_default();
    let mut source_count = 0usize;
    if let Some(items) = value.get("categories").and_then(|item| item.as_array()) {
        for category in items {
            source_count += category
                .get("subcategories")
                .and_then(|item| item.as_array())
                .map(|items| items.len())
                .unwrap_or_default();
        }
    }
    serde_json::to_string(&json!({
        "ok": categories > 0,
        "categories": categories,
        "sources": source_count
    })).unwrap_or_else(|_| "{\"ok\":false}".to_string())
}

#[wasm_bindgen(js_name = mergeLegacyMediaTypes)]
pub fn merge_legacy_media_types(current: &str, legacy: &str) -> String {
    let current_value: Value = serde_json::from_str(current).unwrap_or_else(|_| json!({"categories":[]}));
    let legacy_value: Value = serde_json::from_str(legacy).unwrap_or_else(|_| json!({"categories":[]}));
    let mut categories = current_value
        .get("categories")
        .and_then(|item| item.as_array())
        .cloned()
        .unwrap_or_default();
    if let Some(legacy_categories) = legacy_value.get("categories").and_then(|item| item.as_array()) {
        for category in legacy_categories {
            categories.push(category.clone());
        }
    }
    serde_json::to_string(&json!({
        "layout_version": "2.0.0",
        "categories": categories
    })).unwrap_or_else(|_| "{\"categories\":[]}".to_string())
}

fn parse_version(value: &str) -> Vec<i32> {
    value
        .split('.')
        .map(|part| part.parse::<i32>().unwrap_or_default())
        .collect()
}
