#include "../core_memory/core_memory_private.h"

enum {
    HUNK_TEMP_ALIGNMENT = 16,
    HUNK_TEMP_ALIGN_MASK = HUNK_TEMP_ALIGNMENT - 1,
    COM_ERROR_FATAL = 0,
    COM_ERROR_DROP = 1
};

void *Hunk_AllocateTempMemoryHighInternal(size_t size)
{
    void *ptr;

#if SIZE_MAX > UINT32_MAX
    if (size > hunk.totalSize) {
        Hunk_MemInfo_f();
        Com_Error(COM_ERROR_DROP,
                  "\x15" "Hunk_AllocateTempMemoryHigh: failed on %i",
                  (int32_t)size);
    }
#endif

    hunk.highTemp += size;
    hunk.highTemp =
        (hunk.highTemp + HUNK_TEMP_ALIGN_MASK) &
        ~HUNK_TEMP_ALIGN_MASK;
    if (HUNK_USAGE_EXCEEDS_TOTAL(hunk.highTemp, hunk.lowTemp)) {
        Hunk_MemInfo_f();
        Com_Error(COM_ERROR_DROP,
                  "\x15" "Hunk_AllocateTempMemoryHigh: failed on %i",
                  (int32_t)size);
    }

    ptr = hunk_base + hunk.totalSize - hunk.highTemp;
    return ptr;
}

void Hunk_ClearTempMemoryHigh(void)
{
    hunk.highTemp = hunk.highUsed;
}

void Hunk_CommitTempMemory(void)
{
    hunk.lowUsed = hunk.lowTemp;
}

void *Hunk_AllocateTempMemory(size_t size)
{
    coduo_hunk_temp_header_t *header;
    size_t headerOffset;
    size_t previousLowTemp;

    if (hunk_base == NULL) {
        return Z_Malloc(size);
    }

#if SIZE_MAX > UINT32_MAX
    if (size > hunk.totalSize) {
        Hunk_MemInfo_f();
        Com_Error(COM_ERROR_DROP,
                  "\x15" "Hunk_AllocateTempMemory: failed on %i, needs %i",
                  (int32_t)size,
                  (int32_t)(size - hunk.totalSize));
    }
#endif

    size += sizeof(*header);
    previousLowTemp = hunk.lowTemp;
    hunk.lowTemp =
        (hunk.lowTemp + HUNK_TEMP_ALIGN_MASK) &
        ~HUNK_TEMP_ALIGN_MASK;
    headerOffset = hunk.lowTemp;
    hunk.lowTemp += size;

    if (HUNK_USAGE_EXCEEDS_TOTAL(hunk.highTemp, hunk.lowTemp)) {
        Hunk_MemInfo_f();
        Com_Error(COM_ERROR_DROP,
                  "\x15" "Hunk_AllocateTempMemory: failed on %i, needs %i",
                  (int32_t)size,
                  (int32_t)(hunk.highTemp + hunk.lowTemp - hunk.totalSize));
    }

    header = (coduo_hunk_temp_header_t *)(hunk_base + headerOffset);
    header->magic = CODUO_HUNK_TEMP_MAGIC;
    header->sizeDelta = hunk.lowTemp - previousLowTemp;
    return header + 1;
}

void *Hunk_ReallocateTempMemory(size_t size)
{
#if SIZE_MAX > UINT32_MAX
    if (size > hunk.totalSize) {
        Hunk_MemInfo_f();
        Com_Error(COM_ERROR_DROP,
                  "\x15" "Hunk_ReallocateTempMemory: failed on %i",
                  (int32_t)size);
    }
#endif

    hunk.lowTemp = hunk.lowUsed + size;
    if (HUNK_USAGE_EXCEEDS_TOTAL(hunk.highTemp, hunk.lowTemp)) {
        Hunk_MemInfo_f();
        Com_Error(COM_ERROR_DROP,
                  "\x15" "Hunk_ReallocateTempMemory: failed on %i",
                  (int32_t)size);
    }

    return hunk_base + hunk.lowUsed;
}

void Hunk_ClearToLowTempMark(void)
{
    hunk.lowTemp = hunk.lowTempMark;
}

void Hunk_SetLowTempMark(void)
{
    hunk.lowTempMark = hunk.lowTemp;
}

void Hunk_FreeTempMemory(void *ptr)
{
    coduo_hunk_temp_header_t *header;

    if (hunk_base == NULL) {
        Z_Free(ptr);
        return;
    }

    header = (coduo_hunk_temp_header_t *)((uint8_t *)ptr - sizeof(*header));
    if (header->magic != CODUO_HUNK_TEMP_MAGIC) {
        Com_Error(COM_ERROR_FATAL,
                  "\x15" "Hunk_FreeTempMemory: bad magic");
    }

    header->magic = CODUO_HUNK_FREED_MAGIC;
    hunk.lowTemp -= header->sizeDelta;
}

void Hunk_ClearTempMemory(void)
{
    if (hunk_base != NULL) {
        hunk.lowTemp = hunk.lowUsed;
    }
}

size_t Hunk_ConvertTempToPermLowInternal(void)
{
    size_t oldLowUsed;

    oldLowUsed = hunk.lowUsed;
    hunk.lowUsed = hunk.lowTemp;
    return oldLowUsed;
}

void Hunk_SetLowUsedInternal(size_t lowUsed)
{
    hunk.lowUsed = lowUsed;
}

/*
 * Checked 2026-06-29: recovered hunk temp address-band no-op; no source-level
 * name proven.
 */
void FUN_0806c7df(void)
{
}
