// Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved.

//! Request handler registry for message dispatch.
//!
//! Maps message types (`u32`) to (handler, freecb) pairs registered by plugins.

use std::collections::HashMap;
use std::sync::OnceLock;

use parking_lot::Mutex;

use crate::types::{KdcFreeResponsePtr, KdcRequestHandlerCbFunc};

struct HandlerEntry {
    handler: KdcRequestHandlerCbFunc,
    free: KdcFreeResponsePtr,
}

static HANDLERS: OnceLock<Mutex<HashMap<u32, HandlerEntry>>> = OnceLock::new();

fn get_registry() -> &'static Mutex<HashMap<u32, HandlerEntry>> {
    HANDLERS.get_or_init(|| Mutex::new(HashMap::new()))
}

#[no_mangle]
pub extern "C" fn register_handler(
    msg_type: u32,
    handler: KdcRequestHandlerCbFunc,
    free: KdcFreeResponsePtr,
) -> u32 {
    let registry = get_registry();
    let mut map = registry.lock();
    if map.contains_key(&msg_type) {
        log::warn!("handler registration rejected: msg_type {} already registered", msg_type);
        return 1;
    }
    map.insert(msg_type, HandlerEntry { handler, free });
    0
}

#[no_mangle]
pub extern "C" fn unregister_handler(msg_type: u32) -> u32 {
    let registry = get_registry();
    let mut map = registry.lock();
    if map.remove(&msg_type).is_some() {
        0
    } else {
        log::warn!("handler unregistration skipped: msg_type {} not found", msg_type);
        1
    }
}

pub fn get_handler(msg_type: u32) -> Option<(KdcRequestHandlerCbFunc, KdcFreeResponsePtr)> {
    let registry = get_registry();
    let map = registry.lock();
    map.get(&msg_type).map(|entry| (entry.handler, entry.free))
}

#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
    use super::*;
    use crate::types::{KdcRequestMsg, KdcResponseMsg};

    extern "C" fn dummy_handler_a(_req: *const KdcRequestMsg, _res: *mut KdcResponseMsg) -> u32 {
        0
    }

    extern "C" fn dummy_handler_b(_req: *const KdcRequestMsg, _res: *mut KdcResponseMsg) -> u32 {
        1
    }

    extern "C" fn noop_free(_res: *mut KdcResponseMsg) {}

    // Test: verify register_handler returns 0 and get_handler returns Some for a new msg_type
    #[test]
    fn test_register_and_get_handler() {
        let _ = unregister_handler(1);
        let result = register_handler(1, dummy_handler_a, noop_free);
        assert_eq!(result, 0);
        let handler = get_handler(1);
        assert!(handler.is_some());
        let _ = unregister_handler(1);
    }

    // Test: verify duplicate registration of the same msg_type returns error code 1
    #[test]
    fn test_register_duplicate_returns_error() {
        let _ = unregister_handler(100);
        let result = register_handler(100, dummy_handler_a, noop_free);
        assert_eq!(result, 0);
        let result = register_handler(100, dummy_handler_b, noop_free);
        assert_eq!(result, 1);
        let _ = unregister_handler(100);
    }

    // Test: verify unregister_handler returns 1 for a non-existent msg_type
    #[test]
    fn test_unregister_nonexistent_returns_error() {
        let result = unregister_handler(999);
        assert_eq!(result, 1);
    }

    // Test: verify get_handler returns None for an unregistered msg_type
    #[test]
    fn test_get_handler_unregistered_returns_none() {
        let _ = unregister_handler(2);
        assert!(get_handler(2).is_none());
    }

    // Test: verify unregister after register returns 0 and subsequent get returns None
    #[test]
    fn test_unregister_clears_handler() {
        let _ = unregister_handler(400);
        let _ = register_handler(400, dummy_handler_a, noop_free);
        assert!(get_handler(400).is_some());
        let result = unregister_handler(400);
        assert_eq!(result, 0);
        assert!(get_handler(400).is_none());
    }

    // Test: verify registering a different handler on a fresh msg_type succeeds independently
    #[test]
    fn test_register_second_handler_independent() {
        let _ = unregister_handler(500);
        let _ = unregister_handler(501);
        let r1 = register_handler(500, dummy_handler_a, noop_free);
        let r2 = register_handler(501, dummy_handler_b, noop_free);
        assert_eq!(r1, 0);
        assert_eq!(r2, 0);
        assert!(get_handler(500).is_some());
        assert!(get_handler(501).is_some());
        let _ = unregister_handler(500);
        let _ = unregister_handler(501);
    }

    // Test: verify re-registering after unregister succeeds with 0
    #[test]
    fn test_reregister_after_unregister() {
        let _ = unregister_handler(600);
        assert_eq!(register_handler(600, dummy_handler_a, noop_free), 0);
        assert_eq!(unregister_handler(600), 0);
        assert_eq!(register_handler(600, dummy_handler_b, noop_free), 0);
        let _ = unregister_handler(600);
    }
}