use super::*;

pub(super) unsafe fn append_attach_log() {
    append_log_message(ATTACH_MESSAGE);
}

pub(super) fn append_log_message(message: &[u8]) {
    let handle = unsafe {
        CreateFileA(
            LOG_PATH.as_ptr().cast(),
            FILE_APPEND_DATA,
            FILE_SHARE_READ,
            ptr::null_mut(),
            OPEN_ALWAYS,
            FILE_ATTRIBUTE_NORMAL,
            ptr::null_mut(),
        )
    };
    if handle == INVALID_HANDLE_VALUE {
        return;
    }

    let _ = unsafe { SetFilePointer(handle, 0, ptr::null_mut(), FILE_END) };
    let mut bytes_written = 0_u32;
    let _ = unsafe {
        WriteFile(
            handle,
            message.as_ptr().cast(),
            message.len() as u32,
            &mut bytes_written,
            ptr::null_mut(),
        )
    };
    let _ = unsafe { CloseHandle(handle) };
}

pub(super) fn append_log_line(line: &str) {
    append_log_message(line.as_bytes());
}

pub(super) fn log_auto_load_launch_state(runtime_profile: *mut u8) {
    let startup_selector =
        unsafe { read_u8(runtime_profile.add(RUNTIME_PROFILE_STARTUP_SELECTOR_OFFSET)) };
    let global_active_mode = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let shell_state = unsafe { read_ptr(SHELL_STATE_PTR_ADDR as *const u8) };
    let mode_id = if shell_state.is_null() {
        0
    } else {
        unsafe { read_u32(shell_state.add(SHELL_STATE_ACTIVE_MODE_OFFSET)) as usize }
    };
    let mut line = String::from("rrt-hook: auto load launch state ");
    let _ = write!(
        &mut line,
        "selector=0x{startup_selector:02x} mode_id=0x{mode_id:08x} global_active_mode=0x{global_active_mode:08x} target_mode=0x{SHELL_MODE_STARTUP_LOAD_DISPATCH:08x}\n",
    );
    append_log_line(&line);
}

pub(super) fn log_post_transition_state() {
    let shell_state = unsafe { read_ptr(SHELL_STATE_PTR_ADDR as *const u8) };
    let active_mode_global = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let field_active_mode_object = if shell_state.is_null() {
        0
    } else {
        unsafe { read_ptr(shell_state.add(SHELL_STATE_ACTIVE_MODE_OBJECT_OFFSET)) as usize }
    };
    let runtime_profile = unsafe { read_ptr(RUNTIME_PROFILE_PTR_ADDR as *const u8) };
    let startup_selector = if runtime_profile.is_null() {
        0
    } else {
        unsafe { read_u8(runtime_profile.add(RUNTIME_PROFILE_STARTUP_SELECTOR_OFFSET)) as usize }
    };
    let load_screen_singleton = unsafe { read_ptr(0x006d10b0 as *const u8) };
    let load_screen_scalar = if load_screen_singleton.is_null() {
        0
    } else {
        unsafe { read_u32(load_screen_singleton.add(0x78)) }
    };
    let mut line = String::from("rrt-hook: auto load post-transition state ");
    let _ = write!(
        &mut line,
        "shell_state=0x{:08x} active_mode_global=0x{active_mode_global:08x} field_active_mode_object=0x{field_active_mode_object:08x} load_screen_singleton=0x{:08x} load_screen_scalar=0x{load_screen_scalar:08x} startup_selector=0x{startup_selector:08x}\n",
        shell_state as usize, load_screen_singleton as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_post_transition_service_state() {
    if !AUTO_LOAD_ATTEMPTED.load(Ordering::Acquire) {
        return;
    }
    let count = AUTO_LOAD_POST_TRANSITION_SERVICE_LOG_COUNT.fetch_add(1, Ordering::AcqRel);
    if count >= 8 {
        return;
    }

    let shell_state = unsafe { read_ptr(SHELL_STATE_PTR_ADDR as *const u8) };
    let active_mode_global = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let field_active_mode_object = if shell_state.is_null() {
        0
    } else {
        unsafe { read_ptr(shell_state.add(SHELL_STATE_ACTIVE_MODE_OBJECT_OFFSET)) as usize }
    };
    let runtime_profile = unsafe { read_ptr(RUNTIME_PROFILE_PTR_ADDR as *const u8) };
    let startup_selector = if runtime_profile.is_null() {
        0
    } else {
        unsafe { read_u8(runtime_profile.add(RUNTIME_PROFILE_STARTUP_SELECTOR_OFFSET)) as usize }
    };
    let load_screen_singleton = unsafe { read_ptr(0x006d10b0 as *const u8) };
    let load_screen_scalar = if load_screen_singleton.is_null() {
        0
    } else {
        unsafe { read_u32(load_screen_singleton.add(0x78)) }
    };
    let mut line = String::from("rrt-hook: auto load post-transition service state ");
    let _ = write!(
        &mut line,
        "count=0x{:08x} shell_state=0x{:08x} active_mode_global=0x{active_mode_global:08x} field_active_mode_object=0x{field_active_mode_object:08x} load_screen_singleton=0x{:08x} load_screen_scalar=0x{load_screen_scalar:08x} startup_selector=0x{startup_selector:08x}\n",
        count + 1,
        shell_state as usize,
        load_screen_singleton as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_shell_state_service_entry(this: *mut u8) {
    let count = AUTO_LOAD_SERVICE_ENTRY_LOG_COUNT.fetch_add(1, Ordering::AcqRel) + 1;
    if count > 8 {
        return;
    }
    let gate_mask = unsafe { runtime_saved_world_restore_gate_mask() };
    let mode_id = unsafe { current_mode_id() };
    let active_mode_global = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let field_active_mode_object = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(SHELL_STATE_ACTIVE_MODE_OBJECT_OFFSET)) as usize }
    };
    let field_a0 = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0xa0)) as usize }
    };
    let mut line = String::from("rrt-hook: auto load shell-state service entry ");
    let _ = write!(
        &mut line,
        "count=0x{count:08x} this=0x{:08x} gate_mask=0x{gate_mask:01x} mode_id=0x{mode_id:08x} active_mode_global=0x{active_mode_global:08x} field_active_mode_object=0x{field_active_mode_object:08x} field_a0=0x{field_a0:08x}\n",
        this as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_shell_state_service_return(this: *mut u8, result: i32) {
    let count = AUTO_LOAD_SERVICE_RETURN_LOG_COUNT.fetch_add(1, Ordering::AcqRel) + 1;
    if count > 8 {
        return;
    }
    let gate_mask = unsafe { runtime_saved_world_restore_gate_mask() };
    let mode_id = unsafe { current_mode_id() };
    let active_mode_global = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let field_active_mode_object = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(SHELL_STATE_ACTIVE_MODE_OBJECT_OFFSET)) as usize }
    };
    let field_a0 = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0xa0)) as usize }
    };
    let mut line = String::from("rrt-hook: auto load shell-state service return ");
    let _ = write!(
        &mut line,
        "count=0x{count:08x} this=0x{:08x} result=0x{result:08x} gate_mask=0x{gate_mask:01x} mode_id=0x{mode_id:08x} active_mode_global=0x{active_mode_global:08x} field_active_mode_object=0x{field_active_mode_object:08x} field_a0=0x{field_a0:08x}\n",
        this as usize,
        result = result as u32,
    );
    append_log_line(&line);
}

pub(super) fn log_profile_startup_dispatch_entry(this: *mut u8, arg1: u32, arg2: u32) {
    let startup_selector = unsafe {
        let runtime_profile = read_ptr(RUNTIME_PROFILE_PTR_ADDR as *const u8);
        if runtime_profile.is_null() {
            0
        } else {
            read_u8(runtime_profile.add(RUNTIME_PROFILE_STARTUP_SELECTOR_OFFSET)) as usize
        }
    };
    let mut line = String::from("rrt-hook: auto load startup dispatch entry ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} arg1=0x{arg1:08x} arg2=0x{arg2:08x} selector=0x{startup_selector:08x}\n",
        this as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_profile_startup_dispatch_return(
    this: *mut u8,
    arg1: u32,
    arg2: u32,
    result: i32,
) {
    let active_mode = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let mut line = String::from("rrt-hook: auto load startup dispatch return ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} arg1=0x{arg1:08x} arg2=0x{arg2:08x} result=0x{result:08x} active_mode=0x{active_mode:08x}\n",
        this as usize,
        result = result as u32,
    );
    append_log_line(&line);
}

pub(super) fn log_runtime_reset_entry(this: *mut u8) {
    let field_4cae = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x4cae)) as usize }
    };
    let field_4cb2 = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x4cb2)) as usize }
    };
    let field_66b2 = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x66b2)) as usize }
    };
    let field_66b6 = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x66b6)) as usize }
    };
    let mut line = String::from("rrt-hook: auto load runtime reset entry ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} field_4cae=0x{field_4cae:08x} field_4cb2=0x{field_4cb2:08x} field_66b2=0x{field_66b2:08x} field_66b6=0x{field_66b6:08x}\n",
        this as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_runtime_reset_return(this: *mut u8, result: *mut u8) {
    let field_4cae = if result.is_null() {
        0
    } else {
        unsafe { read_u32(result.add(0x4cae)) as usize }
    };
    let field_4cb2 = if result.is_null() {
        0
    } else {
        unsafe { read_u32(result.add(0x4cb2)) as usize }
    };
    let field_66b2 = if result.is_null() {
        0
    } else {
        unsafe { read_u32(result.add(0x66b2)) as usize }
    };
    let field_66b6 = if result.is_null() {
        0
    } else {
        unsafe { read_u32(result.add(0x66b6)) as usize }
    };
    let mut line = String::from("rrt-hook: auto load runtime reset return ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} result=0x{:08x} field_4cae=0x{field_4cae:08x} field_4cb2=0x{field_4cb2:08x} field_66b2=0x{field_66b2:08x} field_66b6=0x{field_66b6:08x}\n",
        this as usize, result as usize,
    );
    append_log_line(&line);
}

pub(super) fn should_trace_allocator(size: u32) -> bool {
    if size == STARTUP_RUNTIME_OBJECT_SIZE {
        return true;
    }
    AUTO_LOAD_ALLOCATOR_WINDOW_ACTIVE.load(Ordering::Acquire)
        && AUTO_LOAD_ALLOCATOR_WINDOW_LOG_COUNT.load(Ordering::Acquire) < 16
}

pub(super) fn log_allocator_entry(size: u32, count: u32) {
    let mut line = String::from("rrt-hook: auto load allocator entry ");
    let transition_window = AUTO_LOAD_ALLOCATOR_WINDOW_ACTIVE.load(Ordering::Acquire);
    let _ = write!(
        &mut line,
        "count=0x{count:08x} size=0x{size:08x} transition_window={transition_window}\n",
    );
    append_log_line(&line);
}

pub(super) fn log_allocator_return(size: u32, count: u32, result: *mut u8) {
    let mut line = String::from("rrt-hook: auto load allocator return ");
    let _ = write!(
        &mut line,
        "count=0x{count:08x} size=0x{size:08x} result=0x{:08x}\n",
        result as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_load_screen_scalar_entry(this: *mut u8, value_bits: u32) {
    let field_78 = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x78)) }
    };
    let mut line = String::from("rrt-hook: auto load load-screen scalar entry ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} value_bits=0x{value_bits:08x} field_78=0x{field_78:08x}\n",
        this as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_load_screen_scalar_return(this: *mut u8, value_bits: u32, result: u32) {
    let field_78 = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x78)) }
    };
    let mut line = String::from("rrt-hook: auto load load-screen scalar return ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} value_bits=0x{value_bits:08x} result=0x{result:08x} field_78=0x{field_78:08x}\n",
        this as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_load_screen_construct_entry(this: *mut u8) {
    let mut line = String::from("rrt-hook: auto load load-screen construct entry ");
    let _ = write!(&mut line, "this=0x{:08x}\n", this as usize);
    append_log_line(&line);
}

pub(super) fn log_load_screen_construct_return(this: *mut u8, result: *mut u8) {
    let singleton = unsafe { read_ptr(0x006d10b0 as *const u8) } as usize;
    let mut line = String::from("rrt-hook: auto load load-screen construct return ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} result=0x{:08x} singleton=0x{singleton:08x}\n",
        this as usize, result as usize,
    );
    append_log_line(&line);
    if AUTO_LOAD_ALLOCATOR_WINDOW_ACTIVE.load(Ordering::Acquire) {
        AUTO_LOAD_ALLOCATOR_WINDOW_LOG_COUNT.store(0, Ordering::Release);
    }
}

pub(super) fn should_trace_load_screen_message(this: *mut u8) -> bool {
    if !AUTO_LOAD_ATTEMPTED.load(Ordering::Acquire) {
        return false;
    }
    let singleton = unsafe { read_ptr(0x006d10b0 as *const u8) };
    if singleton.is_null() || this != singleton {
        return false;
    }
    AUTO_LOAD_LOAD_SCREEN_MESSAGE_LOG_COUNT.load(Ordering::Acquire) < 16
}

pub(super) fn log_load_screen_message_entry(this: *mut u8, message: *mut u8, count: u32) {
    let message_id = if message.is_null() {
        0
    } else {
        unsafe { read_u32(message) }
    };
    let message_arg8 = if message.is_null() {
        0
    } else {
        unsafe { read_u32(message.add(0x08)) }
    };
    let page = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x78)) }
    };
    let page_substate = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x7c)) }
    };
    let page_kind = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x80)) }
    };
    let startup_runtime = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let mut line = String::from("rrt-hook: auto load load-screen message entry ");
    let _ = write!(
        &mut line,
        "count=0x{count:08x} this=0x{:08x} message=0x{:08x} message_id=0x{message_id:08x} message_arg8=0x{message_arg8:08x} page=0x{page:08x} page_substate=0x{page_substate:08x} page_kind=0x{page_kind:08x} startup_runtime=0x{startup_runtime:08x}\n",
        this as usize, message as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_load_screen_message_return(
    this: *mut u8,
    message: *mut u8,
    count: u32,
    result: i32,
) {
    let page = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x78)) }
    };
    let page_substate = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x7c)) }
    };
    let page_kind = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x80)) }
    };
    let startup_runtime = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let mut line = String::from("rrt-hook: auto load load-screen message return ");
    let _ = write!(
        &mut line,
        "count=0x{count:08x} this=0x{:08x} message=0x{:08x} result=0x{result:08x} page=0x{page:08x} page_substate=0x{page_substate:08x} page_kind=0x{page_kind:08x} startup_runtime=0x{startup_runtime:08x}\n",
        this as usize,
        message as usize,
        result = result as u32,
    );
    append_log_line(&line);
}

pub(super) fn should_trace_runtime_prime() -> bool {
    AUTO_LOAD_RUNTIME_PRIME_LOG_COUNT.load(Ordering::Acquire) < 12
}

pub(super) fn log_runtime_prime_entry(this: *mut u8, count: u32) {
    let list_head = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x04)) as usize }
    };
    let field_0c68 = if this.is_null() {
        0
    } else {
        unsafe { read_u8(this.add(0x0c68)) as usize }
    };
    let field_001c = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x1c)) as usize }
    };
    let load_screen_singleton = unsafe { read_ptr(0x006d10b0 as *const u8) } as usize;
    let startup_runtime = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let mut line = String::from("rrt-hook: auto load shell runtime-prime entry ");
    let _ = write!(
        &mut line,
        "count=0x{count:08x} this=0x{:08x} list_head=0x{list_head:08x} field_0c68=0x{field_0c68:02x} field_1c=0x{field_001c:08x} load_screen_singleton=0x{load_screen_singleton:08x} startup_runtime=0x{startup_runtime:08x}\n",
        this as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_runtime_prime_return(this: *mut u8, count: u32, result: i32) {
    let list_head = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x04)) as usize }
    };
    let field_001c = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x1c)) as usize }
    };
    let load_screen_singleton = unsafe { read_ptr(0x006d10b0 as *const u8) } as usize;
    let startup_runtime = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let mut line = String::from("rrt-hook: auto load shell runtime-prime return ");
    let _ = write!(
        &mut line,
        "count=0x{count:08x} this=0x{:08x} result=0x{result:08x} list_head=0x{list_head:08x} field_1c=0x{field_001c:08x} load_screen_singleton=0x{load_screen_singleton:08x} startup_runtime=0x{startup_runtime:08x}\n",
        this as usize,
        result = result as u32,
    );
    append_log_line(&line);
}

pub(super) fn should_trace_frame_cycle() -> bool {
    AUTO_LOAD_FRAME_CYCLE_LOG_COUNT.load(Ordering::Acquire) < 12
}

pub(super) fn log_frame_cycle_entry(this: *mut u8, count: u32) {
    let field_18 = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x18)) as usize }
    };
    let field_1c = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x1c)) as usize }
    };
    let field_20 = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x20)) as usize }
    };
    let field_28 = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x28)) as usize }
    };
    let flag_55 = if this.is_null() {
        0
    } else {
        unsafe { read_u8(this.add(0x55)) as usize }
    };
    let flag_56 = if this.is_null() {
        0
    } else {
        unsafe { read_u8(this.add(0x56)) as usize }
    };
    let field_58 = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x58)) as usize }
    };
    let startup_runtime = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let mut line = String::from("rrt-hook: auto load shell frame-cycle entry ");
    let _ = write!(
        &mut line,
        "count=0x{count:08x} this=0x{:08x} field_18=0x{field_18:08x} field_1c=0x{field_1c:08x} field_20=0x{field_20:08x} field_28=0x{field_28:08x} flag_55=0x{flag_55:02x} flag_56=0x{flag_56:02x} field_58=0x{field_58:08x} startup_runtime=0x{startup_runtime:08x}\n",
        this as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_frame_cycle_return(this: *mut u8, count: u32, result: i32) {
    let flag_55 = if this.is_null() {
        0
    } else {
        unsafe { read_u8(this.add(0x55)) as usize }
    };
    let flag_56 = if this.is_null() {
        0
    } else {
        unsafe { read_u8(this.add(0x56)) as usize }
    };
    let field_58 = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x58)) as usize }
    };
    let startup_runtime = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let mut line = String::from("rrt-hook: auto load shell frame-cycle return ");
    let _ = write!(
        &mut line,
        "count=0x{count:08x} this=0x{:08x} result=0x{result:08x} flag_55=0x{flag_55:02x} flag_56=0x{flag_56:02x} field_58=0x{field_58:08x} startup_runtime=0x{startup_runtime:08x}\n",
        this as usize,
        result = result as u32,
    );
    append_log_line(&line);
}

pub(super) fn should_trace_object_service() -> bool {
    AUTO_LOAD_ATTEMPTED.load(Ordering::Acquire)
        && AUTO_LOAD_OBJECT_SERVICE_LOG_COUNT.load(Ordering::Acquire) < 16
}

pub(super) fn log_object_service_entry(this: *mut u8, count: u32) {
    let vtable = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this) as usize }
    };
    let field_1d = if this.is_null() {
        0
    } else {
        unsafe { read_u8(this.add(0x1d)) as usize }
    };
    let field_5c = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x5c)) as usize }
    };
    let child_head = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x70)) as usize }
    };
    let child_tail = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x74)) as usize }
    };
    let first_child_vtable = if child_head == 0 {
        0
    } else {
        unsafe { read_ptr(child_head as *const u8) as usize }
    };
    let first_child_call18 = if first_child_vtable == 0 {
        0
    } else {
        unsafe { read_ptr((first_child_vtable + 0x18) as *const u8) as usize }
    };
    let startup_runtime = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let load_screen_singleton = unsafe { read_ptr(0x006d10b0 as *const u8) } as usize;
    let mut line = String::from("rrt-hook: auto load shell object-service entry ");
    let _ = write!(
        &mut line,
        "count=0x{count:08x} this=0x{:08x} vtable=0x{vtable:08x} field_1d=0x{field_1d:02x} field_5c=0x{field_5c:08x} child_head=0x{child_head:08x} child_tail=0x{child_tail:08x} child_call18=0x{first_child_call18:08x} load_screen_singleton=0x{load_screen_singleton:08x} startup_runtime=0x{startup_runtime:08x}\n",
        this as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_object_service_return(this: *mut u8, count: u32, result: i32) {
    let field_1d = if this.is_null() {
        0
    } else {
        unsafe { read_u8(this.add(0x1d)) as usize }
    };
    let child_head = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x70)) as usize }
    };
    let child_tail = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x74)) as usize }
    };
    let startup_runtime = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let mut line = String::from("rrt-hook: auto load shell object-service return ");
    let _ = write!(
        &mut line,
        "count=0x{count:08x} this=0x{:08x} result=0x{result:08x} field_1d=0x{field_1d:02x} child_head=0x{child_head:08x} child_tail=0x{child_tail:08x} startup_runtime=0x{startup_runtime:08x}\n",
        this as usize,
        result = result as u32,
    );
    append_log_line(&line);
}

pub(super) fn should_trace_child_service() -> bool {
    AUTO_LOAD_ATTEMPTED.load(Ordering::Acquire)
        && AUTO_LOAD_CHILD_SERVICE_LOG_COUNT.load(Ordering::Acquire) < 16
}

pub(super) fn log_child_service_entry(this: *mut u8, count: u32) {
    let vtable = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this) as usize }
    };
    let field_4b = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x4b)) as usize }
    };
    let flag_68 = if this.is_null() {
        0
    } else {
        unsafe { read_u8(this.add(0x68)) as usize }
    };
    let flag_6a = if this.is_null() {
        0
    } else {
        unsafe { read_u8(this.add(0x6a)) as usize }
    };
    let field_86 = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x86)) as usize }
    };
    let field_b0 = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0xb0)) as usize }
    };
    let field_b8 = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0xb8)) as usize }
    };
    let startup_runtime = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let load_screen_singleton = unsafe { read_ptr(0x006d10b0 as *const u8) } as usize;
    let mut line = String::from("rrt-hook: auto load shell child-service entry ");
    let _ = write!(
        &mut line,
        "count=0x{count:08x} this=0x{:08x} vtable=0x{vtable:08x} field_4b=0x{field_4b:08x} flag_68=0x{flag_68:02x} flag_6a=0x{flag_6a:02x} field_86=0x{field_86:08x} field_b0=0x{field_b0:08x} field_b8=0x{field_b8:08x} load_screen_singleton=0x{load_screen_singleton:08x} startup_runtime=0x{startup_runtime:08x}\n",
        this as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_child_service_return(this: *mut u8, count: u32, result: i32) {
    let field_b0 = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0xb0)) as usize }
    };
    let startup_runtime = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let mut line = String::from("rrt-hook: auto load shell child-service return ");
    let _ = write!(
        &mut line,
        "count=0x{count:08x} this=0x{:08x} result=0x{result:08x} field_b0=0x{field_b0:08x} startup_runtime=0x{startup_runtime:08x}\n",
        this as usize,
        result = result as u32,
    );
    append_log_line(&line);
}

pub(super) fn log_shell_publish_entry(this: *mut u8, object: *mut u8, flag: u32) {
    let mut line = String::from("rrt-hook: auto load shell publish entry ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} object=0x{:08x} flag=0x{flag:08x}\n",
        this as usize, object as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_shell_publish_return(this: *mut u8, object: *mut u8, flag: u32, result: i32) {
    let active_mode = unsafe { read_ptr(ACTIVE_MODE_PTR_ADDR as *const u8) } as usize;
    let mut line = String::from("rrt-hook: auto load shell publish return ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} object=0x{:08x} flag=0x{flag:08x} result=0x{result:08x} active_mode=0x{active_mode:08x}\n",
        this as usize,
        object as usize,
        result = result as u32,
    );
    append_log_line(&line);
}

pub(super) fn log_shell_unpublish_entry(this: *mut u8, object: *mut u8) {
    let bundle_head = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this) as usize }
    };
    let bundle_tail = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x04)) as usize }
    };
    let object_vtable = if object.is_null() {
        0
    } else {
        unsafe { read_ptr(object) as usize }
    };
    let object_field_04 = if object.is_null() {
        0
    } else {
        unsafe { read_ptr(object.add(0x04)) as usize }
    };
    let object_field_08 = if object.is_null() {
        0
    } else {
        unsafe { read_ptr(object.add(0x08)) as usize }
    };
    let object_field_0c = if object.is_null() {
        0
    } else {
        unsafe { read_ptr(object.add(0x0c)) as usize }
    };
    let object_prev = if object.is_null() {
        0
    } else {
        unsafe { read_ptr(object.add(0x54)) as usize }
    };
    let object_next = if object.is_null() {
        0
    } else {
        unsafe { read_ptr(object.add(0x58)) as usize }
    };
    let object_list_74 = if object.is_null() {
        0
    } else {
        unsafe { read_ptr(object.add(0x74)) as usize }
    };
    let list_field_00 = if object_list_74 == 0 {
        0
    } else {
        unsafe { read_ptr(object_list_74 as *const u8) as usize }
    };
    let list_field_04 = if object_list_74 == 0 {
        0
    } else {
        unsafe { read_u16((object_list_74 as *const u8).add(0x04)) as usize }
    };
    let list_field_4b = if object_list_74 == 0 {
        0
    } else {
        unsafe { read_u32((object_list_74 as *const u8).add(0x4b)) as usize }
    };
    let list_field_8a = if object_list_74 == 0 {
        0
    } else {
        unsafe { read_ptr((object_list_74 as *const u8).add(0x8a)) as usize }
    };
    let list_vcall_04 = if list_field_00 == 0 {
        0
    } else {
        unsafe { read_ptr((list_field_00 as *const u8).add(0x04)) as usize }
    };
    let list2_field_00 = if list_field_8a == 0 {
        0
    } else {
        unsafe { read_ptr(list_field_8a as *const u8) as usize }
    };
    let list2_field_04 = if list_field_8a == 0 {
        0
    } else {
        unsafe { read_u16((list_field_8a as *const u8).add(0x04)) as usize }
    };
    let list2_field_4b = if list_field_8a == 0 {
        0
    } else {
        unsafe { read_u32((list_field_8a as *const u8).add(0x4b)) as usize }
    };
    let list2_field_8a = if list_field_8a == 0 {
        0
    } else {
        unsafe { read_ptr((list_field_8a as *const u8).add(0x8a)) as usize }
    };
    let list2_vcall_04 = if list2_field_00 == 0 {
        0
    } else {
        unsafe { read_ptr((list2_field_00 as *const u8).add(0x04)) as usize }
    };
    let mut line = String::from("rrt-hook: auto load shell unpublish entry ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} object=0x{:08x} bundle_head=0x{bundle_head:08x} bundle_tail=0x{bundle_tail:08x} object_vtable=0x{object_vtable:08x} field_04=0x{object_field_04:08x} field_08=0x{object_field_08:08x} field_0c=0x{object_field_0c:08x} prev=0x{object_prev:08x} next=0x{object_next:08x} list_74=0x{object_list_74:08x} list_00=0x{list_field_00:08x} list_call4=0x{list_vcall_04:08x} list_04=0x{list_field_04:04x} list_4b=0x{list_field_4b:08x} list_8a=0x{list_field_8a:08x} list2_00=0x{list2_field_00:08x} list2_call4=0x{list2_vcall_04:08x} list2_04=0x{list2_field_04:04x} list2_4b=0x{list2_field_4b:08x} list2_8a=0x{list2_field_8a:08x}\n",
        this as usize, object as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_shell_unpublish_return(this: *mut u8, object: *mut u8, result: i32) {
    let mut line = String::from("rrt-hook: auto load shell unpublish return ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} object=0x{:08x} result=0x{result:08x}\n",
        this as usize,
        object as usize,
        result = result as u32,
    );
    append_log_line(&line);
}

pub(super) fn log_shell_object_teardown_entry(this: *mut u8) {
    let object_vtable = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this) as usize }
    };
    let field_04 = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x04)) as usize }
    };
    let field_08 = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x08)) as usize }
    };
    let field_0c = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x0c)) as usize }
    };
    let head_70 = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x70)) as usize }
    };
    let head_74 = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x74)) as usize }
    };
    let mut line = String::from("rrt-hook: auto load shell object teardown entry ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} vtable=0x{object_vtable:08x} field_04=0x{field_04:08x} field_08=0x{field_08:08x} field_0c=0x{field_0c:08x} head_70=0x{head_70:08x} head_74=0x{head_74:08x}\n",
        this as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_shell_object_teardown_return(this: *mut u8, result: i32) {
    let head_70 = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x70)) as usize }
    };
    let head_74 = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x74)) as usize }
    };
    let mut line = String::from("rrt-hook: auto load shell object teardown return ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} result=0x{result:08x} head_70=0x{head_70:08x} head_74=0x{head_74:08x}\n",
        this as usize,
        result = result as u32,
    );
    append_log_line(&line);
}

pub(super) fn log_shell_object_range_remove_entry(this: *mut u8, arg1: u32, arg2: u32, arg3: u32) {
    let head_74 = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x74)) as usize }
    };
    let mut line = String::from("rrt-hook: auto load shell object range-remove entry ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} arg1=0x{arg1:08x} arg2=0x{arg2:08x} arg3=0x{arg3:08x} head_74=0x{head_74:08x}\n",
        this as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_shell_object_range_remove_return(
    this: *mut u8,
    arg1: u32,
    arg2: u32,
    arg3: u32,
    result: i32,
) {
    let head_74 = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x74)) as usize }
    };
    let mut line = String::from("rrt-hook: auto load shell object range-remove return ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} arg1=0x{arg1:08x} arg2=0x{arg2:08x} arg3=0x{arg3:08x} result=0x{result:08x} head_74=0x{head_74:08x}\n",
        this as usize,
        result = result as u32,
    );
    append_log_line(&line);
}

pub(super) fn log_shell_node_vcall_entry(this: *mut u8, record: *mut u8) {
    let node_vtable = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this) as usize }
    };
    let node_type = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this) as usize }
    };
    let node_field_08 = if this.is_null() {
        0
    } else {
        unsafe { read_u32(this.add(0x08)) as usize }
    };
    let node_field_20 = if this.is_null() {
        0
    } else {
        unsafe { read_u8(this.add(0x20)) as usize }
    };
    let record_kind = if record.is_null() {
        0
    } else {
        unsafe { read_u32(record) as usize }
    };
    let record_x = if record.is_null() {
        0
    } else {
        unsafe { read_u32(record.add(0x24)) as usize }
    };
    let record_y = if record.is_null() {
        0
    } else {
        unsafe { read_u32(record.add(0x28)) as usize }
    };
    let mut line = String::from("rrt-hook: auto load shell node-vcall entry ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} node_vtable=0x{node_vtable:08x} node_type=0x{node_type:08x} node_08=0x{node_field_08:08x} node_20=0x{node_field_20:02x} record=0x{:08x} record_kind=0x{record_kind:08x} record_x=0x{record_x:08x} record_y=0x{record_y:08x}\n",
        this as usize, record as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_shell_node_vcall_return(this: *mut u8, record: *mut u8, result: i32) {
    let mut line = String::from("rrt-hook: auto load shell node-vcall return ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} record=0x{:08x} result=0x{result:08x}\n",
        this as usize,
        record as usize,
        result = result as u32,
    );
    append_log_line(&line);
}

pub(super) fn log_shell_remove_node_entry(this: *mut u8, node: *mut u8) {
    let owner_head = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x70)) as usize }
    };
    let owner_tail = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x74)) as usize }
    };
    let node_vtable = if node.is_null() {
        0
    } else {
        unsafe { read_ptr(node) as usize }
    };
    let node_kind = if node.is_null() {
        0
    } else {
        unsafe { read_u16(node.add(0x04)) as usize }
    };
    let node_owner = if node.is_null() {
        0
    } else {
        unsafe { read_u32(node.add(0x4b)) as usize }
    };
    let node_prev = if node.is_null() {
        0
    } else {
        unsafe { read_ptr(node.add(0x8a)) as usize }
    };
    let node_next = if node.is_null() {
        0
    } else {
        unsafe { read_ptr(node.add(0x8e)) as usize }
    };
    let node_call0 = if node_vtable == 0 {
        0
    } else {
        unsafe { read_ptr(node_vtable as *const u8) as usize }
    };
    let mut line = String::from("rrt-hook: auto load shell remove-node entry ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} owner_head=0x{owner_head:08x} owner_tail=0x{owner_tail:08x} node=0x{:08x} node_vtable=0x{node_vtable:08x} node_call0=0x{node_call0:08x} node_kind=0x{node_kind:04x} node_owner=0x{node_owner:08x} node_prev=0x{node_prev:08x} node_next=0x{node_next:08x}\n",
        this as usize, node as usize,
    );
    append_log_line(&line);
}

pub(super) fn log_shell_remove_node_return(this: *mut u8, node: *mut u8, result: i32) {
    let owner_head = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x70)) as usize }
    };
    let owner_tail = if this.is_null() {
        0
    } else {
        unsafe { read_ptr(this.add(0x74)) as usize }
    };
    let mut line = String::from("rrt-hook: auto load shell remove-node return ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} owner_head=0x{owner_head:08x} owner_tail=0x{owner_tail:08x} node=0x{:08x} result=0x{result:08x}\n",
        this as usize,
        node as usize,
        result = result as u32,
    );
    append_log_line(&line);
}

pub(super) fn log_mode2_teardown_entry(this: *mut u8) {
    let mut line = String::from("rrt-hook: auto load mode2 teardown entry ");
    let _ = write!(&mut line, "this=0x{:08x}\n", this as usize);
    append_log_line(&line);
}

pub(super) fn log_mode2_teardown_return(this: *mut u8, result: i32) {
    let mut line = String::from("rrt-hook: auto load mode2 teardown return ");
    let _ = write!(
        &mut line,
        "this=0x{:08x} result=0x{result:08x}\n",
        this as usize,
        result = result as u32,
    );
    append_log_line(&line);
}
