package codes

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import oshi.SystemInfo
import oshi.hardware.CentralProcessor
import oshi.hardware.GlobalMemory
import java.nio.file.Files
import java.nio.file.Path
import java.time.format.DateTimeFormatter
import java.util.function.Consumer


@Suppress("unused")
class Somecodes {
    companion object {
        val current_directory : String = System.getProperty("user.dir")
        val si = SystemInfo()
        val processor: CentralProcessor = si.hardware.processor
        val memory : GlobalMemory = si.hardware.memory
        val datetimeformat1: DateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")

        const val KB_threshold = 1024.0
        const val MB_threshold = KB_threshold * 1024.0
        const val GB_threshold = MB_threshold * 1024.0
        const val TB_threshold = GB_threshold * 1024.0

        /**
         * Converts a size in bytes to a human-readable format.
         * @param size Size in bytes.
         * @return A string representing the size in a human-readable format.
         */
        fun SizetoHuman(size: Long): String {
            return when {
                size < KB_threshold -> "${size}B"
                size < MB_threshold -> String.format("%.2f KB", size / KB_threshold)
                size < GB_threshold -> String.format("%.2f MB", size / MB_threshold)
                size < TB_threshold -> String.format("%.2f GB", size / GB_threshold)
                else -> String.format("%.2f TB", size / TB_threshold)
            }
        }

        /**
         * Get Disk usage using OSHI library.
         * @param path The path to check disk usage, defaults to the current working directory.
         * @return A string representing the disk usage of the file system in a human-readable format.
         */
        fun getDiskUsage(path: String = current_directory) : String {
            return try{
                val p = Path.of(path).toFile()
                if (p.exists() && p.isDirectory){
                    val total = p.totalSpace
                    val free = p.freeSpace
                    val used = total - free
                    String.format("Total: %s, Used: %s, Free: %s, Usage: %.2f%%",
                        SizetoHuman(total),
                        SizetoHuman(used),
                        SizetoHuman(free),
                        (used.toDouble() / total * 100)
                    )
                } else throw Exception()

            } catch (_ : Exception){
                "N/A"
            }
        }

        fun getCPUUsage(cb : Consumer<String>){
            CoroutineScope(Dispatchers.Default).launch {
                val prev = processor.systemCpuLoadTicks
                delay(1000)
                val current = processor.systemCpuLoadTicks

                fun delta(t: CentralProcessor.TickType) = current[t.index] - prev[t.index]

                val idle = delta(CentralProcessor.TickType.IDLE) + delta(CentralProcessor.TickType.IOWAIT)
                val busy =  delta(CentralProcessor.TickType.USER) + delta(CentralProcessor.TickType.SYSTEM) +
                            delta(CentralProcessor.TickType.NICE) + delta(CentralProcessor.TickType.IRQ) +
                            delta(CentralProcessor.TickType.SOFTIRQ)+ delta(CentralProcessor.TickType.STEAL)

                val total = idle + busy
                val usage = if (total > 0) {
                    (busy.toDouble() / total) * 100
                } else {
                    0.0
                }
                cb.accept(String.format("%.2f%%", usage))
            }

        }

        /**
         * Get RAM usage using OSHI library.
         * @return A string representing the total, used, and available memory in a human-readable format.
         */
        fun getMemoryUsage() : String{
            val totalMemory = memory.total
            val availableMemory = memory.available
            val usedMemory = totalMemory - availableMemory
            return String.format("Total: %s, Used: %s, Available: %s, Usage: %.2f%%",
                SizetoHuman(totalMemory),
                SizetoHuman(usedMemory),
                SizetoHuman(availableMemory)
            , (usedMemory.toDouble() / totalMemory * 100))
        }

        fun ValidString(value: Any) : Boolean {
            return value is String && value.isNotBlank()
        }

        fun ValidFile(value : String) : Boolean {
            if (value.isNotBlank()){
                return Files.exists(Path.of(value))
            }
            return false
        }
    }


}