/*
    * Power.hpp
    * SYS_RESET, SYS_SHUTDOWN, SYS_SUSPEND syscalls
    * Copyright (c) 2026 Daniel Hammer
*/

#pragma once
#include <cstdint>
#include <Efi/UEFI.hpp>
#include <Memory/Paging.hpp>
#include <Io/IoPort.hpp>
#include <Graphics/Framebuffer.hpp>
#include <ACPI/AcpiShutdown.hpp>
#include <ACPI/AcpiSleep.hpp>
#include <ACPI/CpuIdle.hpp>
#include <Hal/CpuPower.hpp>

#include "Syscall.hpp"

namespace montauk::abi {

    // Pending graceful power-off request, set by the desktop and consumed by
    // login.elf. Kernel-global IPC channel (one outstanding request system-wide).
    // `inline` so the single definition is shared across translation units.
    inline int g_pendingPowerAction = POWER_REQ_QUERY;

    // SYS_POWER_REQUEST. action == POWER_REQ_QUERY reads and clears the pending
    // action; any other value records it as the pending action. Returns the
    // pending action for queries, or 0 when recording one.
    static int64_t Sys_PowerRequest(int action) {
        if (action == POWER_REQ_QUERY) {
            int pending = g_pendingPowerAction;
            g_pendingPowerAction = POWER_REQ_QUERY;
            return (int64_t)pending;
        }
        g_pendingPowerAction = action;
        return 0;
    }

    static void Sys_Reset() {
        if (Efi::g_ResetSystem) {
            /* Switch to kernel PML4 which has identity-mapped UEFI runtime regions */
            Memory::VMM::LoadCR3(Memory::VMM::g_paging->PML4);
            Efi::g_ResetSystem(Efi::EfiResetCold, 0, 0, nullptr);
        }

        /* Fallback: triple fault via null IDT */
        struct [[gnu::packed]] { uint16_t limit; uint64_t base; } nullIdt = {0, 0};
        asm volatile("lidt %0; int $0x03" :: "m"(nullIdt));
        __builtin_unreachable();
    }

    static void Sys_Shutdown() {
        /* Primary: ACPI S5 shutdown via PM1 control registers */
        if (Hal::AcpiShutdown::IsAvailable()) {
            Hal::AcpiShutdown::Shutdown();
        }

        /* Fallback: EFI ResetSystem */
        if (Efi::g_ResetSystem) {
            Memory::VMM::LoadCR3(Memory::VMM::g_paging->PML4);
            Efi::g_ResetSystem(Efi::EfiResetShutdown, 0, 0, nullptr);
        }

        /* Last resort: halt the CPU */
        asm volatile("cli; hlt");
        __builtin_unreachable();
    }

    static int64_t Sys_Suspend() {
        if (!Hal::AcpiSleep::IsS3Available()) {
            return -1; // S3 not supported
        }
        return (int64_t)Hal::AcpiSleep::Suspend();
    }

    // SYS_POWERINFO. Fills a CPU power/thermal snapshot. Returns -1 when the
    // CPU exposes no power management features (e.g. under QEMU).
    static int64_t Sys_PowerInfo(PowerInfo* out) {
        Hal::CpuPower::Snapshot s{};
        if (!Hal::CpuPower::GetSnapshot(s)) {
            return -1;
        }

        out->hwpActive   = s.HwpActive ? 1 : 0;
        out->throttling  = s.Throttling ? 1 : 0;
        out->tempC       = s.TempC;
        out->tjMaxC      = s.TjMaxC;
        out->highestPerf = s.HighestPerf;
        out->lowestPerf  = s.LowestPerf;
        out->curMaxPerf  = s.CurMaxPerf;
        out->epp         = s.Epp;
        out->baseMHz     = s.BaseMHz;
        out->maxMHz      = s.MaxMHz;
        out->effMHz      = s.EffMHz;
        out->apIdleHint  = Hal::CpuIdle::GetApIdleHint();
        return 0;
    }
};
