// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
pub const MINIMUM_CPU_UPDATE_INTERVAL : Int = 200

///|
pub let is_supported_system : Bool = is_supported_system_ffi() == 1

///|
pub(all) enum Signal {
  Abort
  Alarm
  Bus
  Child
  Continue
  FloatingPointException
  Hangup
  IO
  IOT
  Illegal
  Interrupt
  Kill
  Pipe
  Poll
  Power
  Profiling
  Quit
  Segv
  Stop
  Sys
  TSTP
  TTIN
  TTOU
  Term
  Trap
  Urgent
  User1
  User2
  VirtualAlarm
  Winch
  XCPU
  XFSZ
} derive(Debug, Eq)

///|
pub let supported_signals : Array[Signal] = [
  Signal::Abort,
  Signal::Alarm,
  Signal::Bus,
  Signal::Child,
  Signal::Continue,
  Signal::FloatingPointException,
  Signal::Hangup,
  Signal::IO,
  Signal::IOT,
  Signal::Illegal,
  Signal::Interrupt,
  Signal::Kill,
  Signal::Pipe,
  Signal::Poll,
  Signal::Power,
  Signal::Profiling,
  Signal::Quit,
  Signal::Segv,
  Signal::Stop,
  Signal::Sys,
  Signal::TSTP,
  Signal::TTIN,
  Signal::TTOU,
  Signal::Term,
  Signal::Trap,
  Signal::Urgent,
  Signal::User1,
  Signal::User2,
  Signal::VirtualAlarm,
  Signal::Winch,
  Signal::XCPU,
  Signal::XFSZ,
]

///|
pub(all) struct Pid {
  value : Int
} derive(Eq, Compare, Hash, Debug)

///|
pub fn Pid::from(value : Int) -> Pid {
  { value, }
}

///|
pub fn Pid::from_u32(value : UInt) -> Pid {
  { value: value.reinterpret_as_int() }
}

///|
pub fn Pid::as_u32(self : Pid) -> UInt {
  if self.value < 0 {
    0
  } else {
    self.value.reinterpret_as_uint()
  }
}

///|
pub fn Pid::to_int(self : Pid) -> Int {
  self.value
}

///|
pub(all) struct Uid {
  value : Int
} derive(Eq, Compare, Hash, Debug)

///|
pub fn Uid::from(value : Int) -> Uid {
  { value, }
}

///|
pub fn Uid::to_int(self : Uid) -> Int {
  self.value
}

///|
pub(all) struct Gid {
  value : Int
} derive(Eq, Compare, Hash, Debug)

///|
pub fn Gid::from(value : Int) -> Gid {
  { value, }
}

///|
pub fn Gid::to_int(self : Gid) -> Int {
  self.value
}

///|
pub(all) struct DiskUsage {
  total_read_bytes : UInt64
  read_bytes : UInt64
  total_written_bytes : UInt64
  written_bytes : UInt64
} derive(Debug, Eq)

///|
pub fn DiskUsage::zero() -> DiskUsage {
  {
    total_read_bytes: 0UL,
    read_bytes: 0UL,
    total_written_bytes: 0UL,
    written_bytes: 0UL,
  }
}

///|
pub(all) struct LoadAvg {
  one : Double
  five : Double
  fifteen : Double
} derive(Debug, Eq)

///|
pub fn LoadAvg::zero() -> LoadAvg {
  { one: 0.0, five: 0.0, fifteen: 0.0 }
}

///|
pub(all) struct CGroupLimits {
  total_memory : UInt64
  free_memory : UInt64
  free_swap : UInt64
} derive(Debug, Eq)

///|
pub(all) enum ProcessStatus {
  Dead
  Idle
  LockBlocked
  Parked
  Run
  Sleep
  Stop
  Suspended
  Tracing
  UninterruptibleDiskSleep
  Unknown(Int)
  Wakekill
  Waking
  Zombie
} derive(Debug, Eq)

///|
pub(all) enum ThreadKind {
  Kernel
  Userland
} derive(Debug, Eq)

///|
pub(all) enum UpdateKind {
  Never
  Always
  OnlyIfNotSet
} derive(Debug, Eq)

///|
pub(all) enum KillError {
  Unsupported
  NotFound
  PermissionDenied
  Timeout
  WaitFailed
  Unknown(String)
} derive(Debug, Eq)

///|
pub(all) enum DiskKind {
  HDD
  SSD
  Unknown(String)
} derive(Debug, Eq)

///|
pub(all) struct MacAddr {
  raw : String
} derive(Debug, Eq)

///|
pub fn MacAddr::is_unspecified(self : MacAddr) -> Bool {
  self.raw == "" || self.raw == "00:00:00:00:00:00"
}

///|
pub fn MacAddr::to_string(self : MacAddr) -> String {
  self.raw
}

///|
pub(all) struct IpNetwork {
  raw : String
} derive(Debug, Eq)

///|
pub fn IpNetwork::to_string(self : IpNetwork) -> String {
  self.raw
}

///|
pub(all) enum ProcessesToUpdate {
  All
  Selected(Array[Pid])
} derive(Debug, Eq)

///|
pub(all) struct ExitStatus {
  code : Int?
  signal : Signal?
  success : Bool
} derive(Debug, Eq)

///|
pub fn ExitStatus::from_code(code : Int) -> ExitStatus {
  { code: Some(code), signal: None, success: code == 0 }
}

///|
pub fn ExitStatus::from_signal(signal : Signal) -> ExitStatus {
  { code: None, signal: Some(signal), success: false }
}

///|
pub(all) struct Cpu {
  mut name : String
  mut vendor_id : String
  mut brand : String
  mut frequency : UInt64
  mut cpu_usage : Double
} derive(Debug, Eq)

///|
pub fn Cpu::cpu_usage(self : Cpu) -> Double {
  self.cpu_usage
}

///|
pub fn Cpu::name(self : Cpu) -> String {
  self.name
}

///|
pub fn Cpu::vendor_id(self : Cpu) -> String {
  self.vendor_id
}

///|
pub fn Cpu::brand(self : Cpu) -> String {
  self.brand
}

///|
pub fn Cpu::frequency(self : Cpu) -> UInt64 {
  self.frequency
}

///|
pub(all) struct Process {
  mut pid : Pid
  mut parent : Pid?
  mut name : String
  mut cmd : Array[String]
  mut environ : Array[String]
  mut exe : String?
  mut cwd : String?
  mut root : String?
  mut memory : UInt64
  mut virtual_memory : UInt64
  mut status : ProcessStatus
  mut start_time : UInt64
  mut run_time : UInt64
  mut cpu_usage : Double
  mut accumulated_cpu_time : UInt64
  mut disk_usage : DiskUsage
  mut user_id : Uid?
  mut effective_user_id : Uid?
  mut group_id : Gid?
  mut effective_group_id : Gid?
  mut session_id : Pid?
  mut tasks : Array[Pid]?
  mut thread_kind : ThreadKind?
  mut open_files : Int?
  mut open_files_limit : Int?
} derive(Debug, Eq)

///|
pub fn Process::pid(self : Process) -> Pid {
  self.pid
}

///|
pub fn Process::name(self : Process) -> String {
  self.name
}

///|
pub fn Process::cmd(self : Process) -> Array[String] {
  self.cmd
}

///|
pub fn Process::exe(self : Process) -> String? {
  self.exe
}

///|
pub fn Process::environ(self : Process) -> Array[String] {
  self.environ
}

///|
pub fn Process::cwd(self : Process) -> String? {
  self.cwd
}

///|
pub fn Process::root(self : Process) -> String? {
  self.root
}

///|
pub fn Process::memory(self : Process) -> UInt64 {
  self.memory
}

///|
pub fn Process::virtual_memory(self : Process) -> UInt64 {
  self.virtual_memory
}

///|
pub fn Process::parent(self : Process) -> Pid? {
  self.parent
}

///|
pub fn Process::status(self : Process) -> ProcessStatus {
  self.status
}

///|
pub fn Process::start_time(self : Process) -> UInt64 {
  self.start_time
}

///|
pub fn Process::run_time(self : Process) -> UInt64 {
  self.run_time
}

///|
pub fn Process::cpu_usage(self : Process) -> Double {
  self.cpu_usage
}

///|
pub fn Process::accumulated_cpu_time(self : Process) -> UInt64 {
  self.accumulated_cpu_time
}

///|
pub fn Process::disk_usage(self : Process) -> DiskUsage {
  self.disk_usage
}

///|
pub fn Process::user_id(self : Process) -> Uid? {
  self.user_id
}

///|
pub fn Process::effective_user_id(self : Process) -> Uid? {
  self.effective_user_id
}

///|
pub fn Process::group_id(self : Process) -> Gid? {
  self.group_id
}

///|
pub fn Process::effective_group_id(self : Process) -> Gid? {
  self.effective_group_id
}

///|
pub fn Process::session_id(self : Process) -> Pid? {
  self.session_id
}

///|
pub fn Process::tasks(self : Process) -> Array[Pid]? {
  self.tasks
}

///|
pub fn Process::thread_kind(self : Process) -> ThreadKind? {
  self.thread_kind
}

///|
pub fn Process::open_files(self : Process) -> Int? {
  self.open_files
}

///|
pub fn Process::open_files_limit(self : Process) -> Int? {
  self.open_files_limit
}

///|
pub fn Process::exists(self : Process) -> Bool {
  process_exists(self.pid)
}

///|
pub(all) struct Disk {
  mut kind : DiskKind
  mut name : String
  mut file_system : String
  mut mount_point : String
  mut total_space : UInt64
  mut available_space : UInt64
  mut is_removable : Bool
  mut is_read_only : Bool
  mut usage : DiskUsage
} derive(Debug, Eq)

///|
pub fn Disk::kind(self : Disk) -> DiskKind {
  self.kind
}

///|
pub fn Disk::name(self : Disk) -> String {
  self.name
}

///|
pub fn Disk::file_system(self : Disk) -> String {
  self.file_system
}

///|
pub fn Disk::mount_point(self : Disk) -> String {
  self.mount_point
}

///|
pub fn Disk::total_space(self : Disk) -> UInt64 {
  self.total_space
}

///|
pub fn Disk::available_space(self : Disk) -> UInt64 {
  self.available_space
}

///|
pub fn Disk::is_removable(self : Disk) -> Bool {
  self.is_removable
}

///|
pub fn Disk::is_read_only(self : Disk) -> Bool {
  self.is_read_only
}

///|
pub fn Disk::usage(self : Disk) -> DiskUsage {
  self.usage
}

///|
pub(all) struct NetworkData {
  mut received : UInt64
  mut total_received : UInt64
  mut transmitted : UInt64
  mut total_transmitted : UInt64
  mut packets_received : UInt64
  mut total_packets_received : UInt64
  mut packets_transmitted : UInt64
  mut total_packets_transmitted : UInt64
  mut errors_on_received : UInt64
  mut total_errors_on_received : UInt64
  mut errors_on_transmitted : UInt64
  mut total_errors_on_transmitted : UInt64
  mut mac_address : MacAddr
  mut ip_networks : Array[IpNetwork]
  mut mtu : UInt64
} derive(Debug, Eq)

///|
pub fn NetworkData::received(self : NetworkData) -> UInt64 {
  self.received
}

///|
pub fn NetworkData::total_received(self : NetworkData) -> UInt64 {
  self.total_received
}

///|
pub fn NetworkData::transmitted(self : NetworkData) -> UInt64 {
  self.transmitted
}

///|
pub fn NetworkData::total_transmitted(self : NetworkData) -> UInt64 {
  self.total_transmitted
}

///|
pub fn NetworkData::packets_received(self : NetworkData) -> UInt64 {
  self.packets_received
}

///|
pub fn NetworkData::total_packets_received(self : NetworkData) -> UInt64 {
  self.total_packets_received
}

///|
pub fn NetworkData::packets_transmitted(self : NetworkData) -> UInt64 {
  self.packets_transmitted
}

///|
pub fn NetworkData::total_packets_transmitted(self : NetworkData) -> UInt64 {
  self.total_packets_transmitted
}

///|
pub fn NetworkData::errors_on_received(self : NetworkData) -> UInt64 {
  self.errors_on_received
}

///|
pub fn NetworkData::total_errors_on_received(self : NetworkData) -> UInt64 {
  self.total_errors_on_received
}

///|
pub fn NetworkData::errors_on_transmitted(self : NetworkData) -> UInt64 {
  self.errors_on_transmitted
}

///|
pub fn NetworkData::total_errors_on_transmitted(self : NetworkData) -> UInt64 {
  self.total_errors_on_transmitted
}

///|
pub fn NetworkData::mac_address(self : NetworkData) -> MacAddr {
  self.mac_address
}

///|
pub fn NetworkData::ip_networks(self : NetworkData) -> Array[IpNetwork] {
  self.ip_networks
}

///|
pub fn NetworkData::mtu(self : NetworkData) -> UInt64 {
  self.mtu
}

///|
pub(all) struct Component {
  mut temperature : Double?
  mut max : Double?
  mut critical : Double?
  mut label : String
  mut id : String?
} derive(Debug, Eq)

///|
pub fn Component::temperature(self : Component) -> Double? {
  self.temperature
}

///|
pub fn Component::max(self : Component) -> Double? {
  self.max
}

///|
pub fn Component::critical(self : Component) -> Double? {
  self.critical
}

///|
pub fn Component::label(self : Component) -> String {
  self.label
}

///|
pub fn Component::id(self : Component) -> String? {
  self.id
}

///|
pub(all) struct Group {
  mut id : Gid
  mut name : String
} derive(Debug, Eq)

///|
pub fn Group::id(self : Group) -> Gid {
  self.id
}

///|
pub fn Group::name(self : Group) -> String {
  self.name
}

///|
pub(all) struct User {
  mut id : Uid
  mut group_id : Gid
  mut name : String
  mut groups : Array[Group]
} derive(Debug, Eq)

///|
pub fn User::id(self : User) -> Uid {
  self.id
}

///|
pub fn User::group_id(self : User) -> Gid {
  self.group_id
}

///|
pub fn User::name(self : User) -> String {
  self.name
}

///|
pub fn User::groups(self : User) -> Array[Group] {
  self.groups
}