use crate::error::RariError;
use serde_json::Value as JsonValue;

pub const CHANNEL_CAPACITY: usize = 32;
pub const RUNTIME_RESTART_DELAY_MS: u64 = 1000;
pub const RUNTIME_QUICK_RESTART_DELAY_MS: u64 = 100;
pub const COMPONENT_PREFIX: &str = "component_";
pub const VERIFY_REGISTRATION_PREFIX: &str = "verify_registration_";
pub const RARI_REGISTER_FUNCTION: &str = "__rari_register";

pub const MODULE_ALREADY_EVALUATED_ERROR: &str = "Module already evaluated";
pub const JS_EXECUTOR_FAILED_ERROR: &str = "JS executor failed to respond";
pub const JS_EXECUTOR_CHANNEL_CLOSED_ERROR: &str = "JS executor channel closed";
pub const RUNTIME_RESTART_MESSAGE: &str =
    "Runtime is being restarted for stability. Please retry your request.";

pub const ENV_INJECTION_SCRIPT: &str = r#"
(() => {
    if (!globalThis.process.env) {
        globalThis.process.env = {};
    }

    const envVars = {};
    Object.assign(globalThis.process.env, envVars);

    return Object.keys(envVars).length;
})();
"#;

pub const MODULE_CHECK_SCRIPT: &str = r#"
(function() {
    if (!globalThis.RscModuleManager) {
        return { available: false, extension: 'rsc_modules' };
    }
    return { available: true, extension: 'rsc_modules' };
})()
"#;

pub const PROMISE_SETUP_SCRIPT: &str = r#"
(function() {
    try {
        const promise = globalThis.__current_promise_object;
        if (!promise || typeof promise.then !== 'function') {
            globalThis.__promise_resolved_value = {
                __error: "Not a valid promise",
                received: typeof promise,
                promiseToString: String(promise)
            };
            globalThis.__promise_resolution_complete = true;
            return;
        }

        globalThis.__promise_resolved_value = null;
        globalThis.__promise_resolution_complete = false;

        promise.then(function(resolvedValue) {
            globalThis.__promise_resolved_value = resolvedValue;
            globalThis.__promise_resolution_complete = true;
        }).catch(function(error) {
            globalThis.__promise_resolved_value = {
                __promise_error: true,
                error: String(error),
                stack: error.stack || "No stack trace"
            };
            globalThis.__promise_resolution_complete = true;
        });
    } catch (error) {
        globalThis.__promise_resolved_value = {
            __promise_error: true,
            error: String(error),
            stack: error.stack || "No stack trace"
        };
        globalThis.__promise_resolution_complete = true;
    }
})()
"#;

pub const PROMISE_EXTRACT_SCRIPT: &str = r#"
(function() {
    if (globalThis.__promise_resolution_complete === true) {
        return globalThis.__promise_resolved_value;
    } else {
        return {
            __timeout_error: "Promise did not resolve in time",
            __debug_info: {
                completion_flag: globalThis.__promise_resolution_complete,
                resolved_value: globalThis.__promise_resolved_value
            }
        };
    }
})()
"#;

// Helper functions
pub fn is_critical_error(error: &RariError) -> bool {
    let error_str = error.to_string();
    error_str.contains("assertion") || error_str.contains("panicked")
}

pub fn is_runtime_restart_needed(error: &RariError) -> bool {
    let error_str = error.to_string();
    error_str.contains(MODULE_ALREADY_EVALUATED_ERROR)
        || error_str.contains(JS_EXECUTOR_FAILED_ERROR)
        || error_str.contains(JS_EXECUTOR_CHANNEL_CLOSED_ERROR)
}

pub fn create_graceful_error() -> RariError {
    RariError::js_runtime(RUNTIME_RESTART_MESSAGE.to_string())
}

#[allow(clippy::disallowed_methods)]
pub fn create_already_evaluated_response(component_name: &str) -> JsonValue {
    serde_json::json!({
        "status": "already_evaluated",
        "component": component_name
    })
}

#[allow(clippy::disallowed_methods)]
pub fn create_already_loaded_response(component_name: &str) -> JsonValue {
    serde_json::json!({
        "status": "already_loaded",
        "component": component_name
    })
}

pub fn create_registration_script(specifier_str: &str, script_name: &str) -> String {
    format!(
        r#"
        (async function() {{
            try {{
                const module = await import("{specifier_str}");
                if (typeof module.{RARI_REGISTER_FUNCTION} === 'function') {{
                    const result = module.{RARI_REGISTER_FUNCTION}.call(module);
                    return {{ success: true, result }};
                }} else {{
                    return {{ success: false, error: 'No {RARI_REGISTER_FUNCTION} function found' }};
                }}
            }} catch (e) {{
                console.error("[RARI_ERROR] Failed to call {RARI_REGISTER_FUNCTION} for '{script_name}': " + e.message);
                return {{ success: false, error: e.message }};
            }}
        }})()
        "#
    )
}
