use super::*;

pub(super) unsafe extern "fastcall" fn shell_state_service_detour(
    this: *mut u8,
    _edx: usize,
) -> i32 {
    log_shell_state_service_entry(this);
    let trampoline: ShellStateServiceFn = unsafe { mem::transmute(SHELL_STATE_SERVICE_TRAMPOLINE) };
    let result = unsafe { trampoline(this) };
    log_shell_state_service_return(this, result);
    log_post_transition_service_state();
    maybe_service_auto_load_on_main_thread();
    result
}

pub(super) unsafe extern "fastcall" fn profile_startup_dispatch_detour(
    this: *mut u8,
    _edx: usize,
    arg1: u32,
    arg2: u32,
) -> i32 {
    log_profile_startup_dispatch_entry(this, arg1, arg2);
    append_log_message(AUTO_LOAD_PROFILE_DISPATCH_ENTRY_MESSAGE);
    let trampoline: ProfileStartupDispatchFn =
        unsafe { mem::transmute(PROFILE_STARTUP_DISPATCH_TRAMPOLINE) };
    let result = unsafe { trampoline(this, arg1, arg2) };
    append_log_message(AUTO_LOAD_PROFILE_DISPATCH_RETURNED_MESSAGE);
    log_profile_startup_dispatch_return(this, arg1, arg2, result);
    result
}

pub(super) unsafe extern "fastcall" fn runtime_reset_detour(this: *mut u8, _edx: usize) -> *mut u8 {
    append_log_message(AUTO_LOAD_RUNTIME_RESET_ENTRY_MESSAGE);
    log_runtime_reset_entry(this);
    let trampoline: RuntimeResetFn = unsafe { mem::transmute(RUNTIME_RESET_TRAMPOLINE) };
    let result = unsafe { trampoline(this) };
    append_log_message(AUTO_LOAD_RUNTIME_RESET_RETURNED_MESSAGE);
    log_runtime_reset_return(this, result);
    result
}

pub(super) unsafe extern "cdecl" fn allocator_detour(size: u32) -> *mut u8 {
    let trace = should_trace_allocator(size);
    let count = if trace {
        AUTO_LOAD_ALLOCATOR_WINDOW_LOG_COUNT.fetch_add(1, Ordering::AcqRel) + 1
    } else {
        0
    };
    if trace {
        append_log_message(AUTO_LOAD_ALLOCATOR_ENTRY_MESSAGE);
        log_allocator_entry(size, count);
    }
    let original: StartupRuntimeAllocThunkFn = unsafe { mem::transmute(0x005a125dusize) };
    let result = unsafe { original(size) };
    if trace {
        append_log_message(AUTO_LOAD_ALLOCATOR_RETURNED_MESSAGE);
        log_allocator_return(size, count, result);
    }
    result
}

pub(super) unsafe extern "fastcall" fn load_screen_scalar_detour(
    this: *mut u8,
    _edx: usize,
    value_bits: u32,
) -> u32 {
    append_log_message(AUTO_LOAD_LOAD_SCREEN_SCALAR_ENTRY_MESSAGE);
    log_load_screen_scalar_entry(this, value_bits);
    let trampoline: LoadScreenSetScalarFn =
        unsafe { mem::transmute(LOAD_SCREEN_SCALAR_TRAMPOLINE) };
    let result = unsafe { trampoline(this, value_bits) };
    append_log_message(AUTO_LOAD_LOAD_SCREEN_SCALAR_RETURNED_MESSAGE);
    log_load_screen_scalar_return(this, value_bits, result);
    result
}

pub(super) unsafe extern "fastcall" fn load_screen_construct_detour(
    this: *mut u8,
    _edx: usize,
) -> *mut u8 {
    append_log_message(AUTO_LOAD_LOAD_SCREEN_ENTRY_MESSAGE);
    log_load_screen_construct_entry(this);
    let trampoline: LoadScreenConstructFn =
        unsafe { mem::transmute(LOAD_SCREEN_CONSTRUCT_TRAMPOLINE) };
    let result = unsafe { trampoline(this) };
    append_log_message(AUTO_LOAD_LOAD_SCREEN_RETURNED_MESSAGE);
    log_load_screen_construct_return(this, result);
    result
}

pub(super) unsafe extern "fastcall" fn load_screen_message_detour(
    this: *mut u8,
    _edx: usize,
    message: *mut u8,
) -> i32 {
    let trace = should_trace_load_screen_message(this);
    let count = if trace {
        AUTO_LOAD_LOAD_SCREEN_MESSAGE_LOG_COUNT.fetch_add(1, Ordering::AcqRel) + 1
    } else {
        0
    };
    if trace {
        append_log_message(AUTO_LOAD_LOAD_SCREEN_MESSAGE_ENTRY_MESSAGE);
        log_load_screen_message_entry(this, message, count);
    }
    let trampoline: LoadScreenHandleMessageFn =
        unsafe { mem::transmute(LOAD_SCREEN_MESSAGE_TRAMPOLINE) };
    let result = unsafe { trampoline(this, message) };
    if trace {
        append_log_message(AUTO_LOAD_LOAD_SCREEN_MESSAGE_RETURNED_MESSAGE);
        log_load_screen_message_return(this, message, count, result);
    }
    result
}

pub(super) unsafe extern "fastcall" fn runtime_prime_detour(this: *mut u8, _edx: usize) -> i32 {
    let trace = should_trace_runtime_prime();
    let count = if trace {
        AUTO_LOAD_RUNTIME_PRIME_LOG_COUNT.fetch_add(1, Ordering::AcqRel) + 1
    } else {
        0
    };
    if trace {
        append_log_message(AUTO_LOAD_RUNTIME_PRIME_ENTRY_MESSAGE);
        log_runtime_prime_entry(this, count);
    }
    let trampoline: ShellRuntimePrimeFn = unsafe { mem::transmute(RUNTIME_PRIME_TRAMPOLINE) };
    let result = unsafe { trampoline(this) };
    if trace {
        append_log_message(AUTO_LOAD_RUNTIME_PRIME_RETURNED_MESSAGE);
        log_runtime_prime_return(this, count, result);
    }
    result
}

pub(super) unsafe extern "fastcall" fn frame_cycle_detour(this: *mut u8, _edx: usize) -> i32 {
    let trace = should_trace_frame_cycle();
    let count = if trace {
        AUTO_LOAD_FRAME_CYCLE_LOG_COUNT.fetch_add(1, Ordering::AcqRel) + 1
    } else {
        0
    };
    if trace {
        append_log_message(AUTO_LOAD_FRAME_CYCLE_ENTRY_MESSAGE);
        log_frame_cycle_entry(this, count);
    }
    let trampoline: ShellFrameCycleFn = unsafe { mem::transmute(FRAME_CYCLE_TRAMPOLINE) };
    let result = unsafe { trampoline(this) };
    if trace {
        append_log_message(AUTO_LOAD_FRAME_CYCLE_RETURNED_MESSAGE);
        log_frame_cycle_return(this, count, result);
    }
    result
}

pub(super) unsafe extern "fastcall" fn object_service_detour(this: *mut u8, _edx: usize) -> i32 {
    let trace = should_trace_object_service();
    let count = if trace {
        AUTO_LOAD_OBJECT_SERVICE_LOG_COUNT.fetch_add(1, Ordering::AcqRel) + 1
    } else {
        0
    };
    if trace {
        append_log_message(AUTO_LOAD_OBJECT_SERVICE_ENTRY_MESSAGE);
        log_object_service_entry(this, count);
    }
    let trampoline: ShellObjectServiceFn = unsafe { mem::transmute(OBJECT_SERVICE_TRAMPOLINE) };
    let result = unsafe { trampoline(this) };
    if trace {
        append_log_message(AUTO_LOAD_OBJECT_SERVICE_RETURNED_MESSAGE);
        log_object_service_return(this, count, result);
    }
    result
}

pub(super) unsafe extern "fastcall" fn child_service_detour(this: *mut u8, _edx: usize) -> i32 {
    let trace = should_trace_child_service();
    let count = if trace {
        AUTO_LOAD_CHILD_SERVICE_LOG_COUNT.fetch_add(1, Ordering::AcqRel) + 1
    } else {
        0
    };
    if trace {
        append_log_message(AUTO_LOAD_CHILD_SERVICE_ENTRY_MESSAGE);
        log_child_service_entry(this, count);
    }
    let trampoline: ShellChildServiceFn = unsafe { mem::transmute(CHILD_SERVICE_TRAMPOLINE) };
    let result = unsafe { trampoline(this) };
    if trace {
        append_log_message(AUTO_LOAD_CHILD_SERVICE_RETURNED_MESSAGE);
        log_child_service_return(this, count, result);
    }
    result
}

pub(super) unsafe extern "fastcall" fn shell_publish_detour(
    this: *mut u8,
    _edx: usize,
    object: *mut u8,
    flag: u32,
) -> i32 {
    append_log_message(AUTO_LOAD_PUBLISH_ENTRY_MESSAGE);
    log_shell_publish_entry(this, object, flag);
    let trampoline: ShellPublishWindowFn = unsafe { mem::transmute(SHELL_PUBLISH_TRAMPOLINE) };
    let result = unsafe { trampoline(this, object, flag) };
    append_log_message(AUTO_LOAD_PUBLISH_RETURNED_MESSAGE);
    log_shell_publish_return(this, object, flag, result);
    result
}

pub(super) unsafe extern "fastcall" fn shell_unpublish_detour(
    this: *mut u8,
    _edx: usize,
    object: *mut u8,
) -> i32 {
    append_log_message(AUTO_LOAD_UNPUBLISH_ENTRY_MESSAGE);
    log_shell_unpublish_entry(this, object);
    let trampoline: ShellUnpublishWindowFn = unsafe { mem::transmute(SHELL_UNPUBLISH_TRAMPOLINE) };
    let result = unsafe { trampoline(this, object) };
    append_log_message(AUTO_LOAD_UNPUBLISH_RETURNED_MESSAGE);
    log_shell_unpublish_return(this, object, result);
    result
}

pub(super) unsafe extern "fastcall" fn shell_object_range_remove_detour(
    this: *mut u8,
    _edx: usize,
    arg1: u32,
    arg2: u32,
    arg3: u32,
) -> i32 {
    append_log_message(AUTO_LOAD_OBJECT_RANGE_REMOVE_ENTRY_MESSAGE);
    log_shell_object_range_remove_entry(this, arg1, arg2, arg3);
    let trampoline: ShellObjectRangeRemoveFn =
        unsafe { mem::transmute(SHELL_OBJECT_RANGE_REMOVE_TRAMPOLINE) };
    let result = unsafe { trampoline(this, arg1, arg2, arg3) };
    append_log_message(AUTO_LOAD_OBJECT_RANGE_REMOVE_RETURNED_MESSAGE);
    log_shell_object_range_remove_return(this, arg1, arg2, arg3, result);
    result
}

pub(super) unsafe extern "fastcall" fn shell_object_teardown_detour(
    this: *mut u8,
    _edx: usize,
) -> i32 {
    append_log_message(AUTO_LOAD_OBJECT_TEARDOWN_ENTRY_MESSAGE);
    log_shell_object_teardown_entry(this);
    let trampoline: ShellObjectTeardownFn =
        unsafe { mem::transmute(SHELL_OBJECT_TEARDOWN_TRAMPOLINE) };
    let result = unsafe { trampoline(this) };
    append_log_message(AUTO_LOAD_OBJECT_TEARDOWN_RETURNED_MESSAGE);
    log_shell_object_teardown_return(this, result);
    result
}

pub(super) unsafe extern "fastcall" fn shell_node_vcall_detour(
    this: *mut u8,
    _edx: usize,
    record: *mut u8,
) -> i32 {
    append_log_message(AUTO_LOAD_NODE_VCALL_ENTRY_MESSAGE);
    log_shell_node_vcall_entry(this, record);
    let trampoline: ShellNodeVcallFn = unsafe { mem::transmute(SHELL_NODE_VCALL_TRAMPOLINE) };
    let result = unsafe { trampoline(this, record) };
    append_log_message(AUTO_LOAD_NODE_VCALL_RETURNED_MESSAGE);
    log_shell_node_vcall_return(this, record, result);
    result
}

pub(super) unsafe extern "fastcall" fn shell_remove_node_detour(
    this: *mut u8,
    _edx: usize,
    node: *mut u8,
) -> i32 {
    append_log_message(AUTO_LOAD_REMOVE_NODE_ENTRY_MESSAGE);
    log_shell_remove_node_entry(this, node);
    let trampoline: ShellRemoveNodeFn = unsafe { mem::transmute(SHELL_REMOVE_NODE_TRAMPOLINE) };
    let result = unsafe { trampoline(this, node) };
    append_log_message(AUTO_LOAD_REMOVE_NODE_RETURNED_MESSAGE);
    log_shell_remove_node_return(this, node, result);
    result
}

pub(super) unsafe extern "fastcall" fn mode2_teardown_detour(this: *mut u8, _edx: usize) -> i32 {
    append_log_message(AUTO_LOAD_MODE2_TEARDOWN_ENTRY_MESSAGE);
    log_mode2_teardown_entry(this);
    let trampoline: Mode2TeardownFn = unsafe { mem::transmute(MODE2_TEARDOWN_TRAMPOLINE) };
    let result = unsafe { trampoline(this) };
    append_log_message(AUTO_LOAD_MODE2_TEARDOWN_RETURNED_MESSAGE);
    log_mode2_teardown_return(this, result);
    result
}
