import Darwin
import SiliconPulseSMC

struct SMCThermalSensorReader: Sendable {
    private static let cpuKeys: [String] = [
        "Te04", "Te05", "Te06", "Te0R", "Te0S", "Te0T",
        "Tf04", "Tf06", "Tf08", "Tf09", "Tf0A", "Tf0B",
        "Tf14", "Tf16", "Tf18", "Tf19", "Tf1A", "Tf1B",
        "Tf24", "Tf26", "Tf28", "Tf29", "Tf2A", "Tf2B",
        "Tf34", "Tf36", "Tf38", "Tf39", "Tf3A", "Tf3B",
        "Tf44", "Tf46", "Tf48", "Tf49", "Tf4A", "Tf4B",
    ]

    private static let gpuKeys: [String] = [
        "Tg04", "Tg05", "Tg0K", "Tg0L", "Tg0R", "Tg0S",
        "Tg0X", "Tg0Y", "Tg0d", "Tg0e", "Tg0j", "Tg0k",
        "Tg0y", "Tg0z", "Tg1E", "Tg1F", "Tg1U", "Tg1V",
        "Tg1c", "Tg1d", "Tg1k", "Tg1l", "Tg21", "Tg22",
        "Tg2H", "Tg2I", "Tg2P", "Tg2Q", "Tg2X", "Tg2Y",
        "Tg2f", "Tg2g", "Tg2n", "Tg2o", "Tg33", "Tg34",
        "Tg3J", "Tg3K", "Tg3Z", "Tg3a", "Tg3h", "Tg3i",
        "Tg3p", "Tg3q",
    ]

    func readSensors() -> [ThermalSensorReading] {
        Self.read(keys: Self.cpuKeys + Self.gpuKeys)
    }

    private static func read(keys: [String]) -> [ThermalSensorReading] {
        let cStrings = keys.map { strdup($0)! }
        defer {
            for pointer in cStrings {
                free(pointer)
            }
        }

        var keyPointers = cStrings.map { Optional(UnsafePointer<CChar>($0)) }
        var values = Array(repeating: 0.0, count: keys.count)
        var valid = Array(repeating: Int32(0), count: keys.count)
        let count = keyPointers.withUnsafeMutableBufferPointer { buffer in
            SiliconPulseSMCReadTemperatures(buffer.baseAddress, Int32(keys.count), &values, &valid)
        }
        guard count > 0 else { return [] }

        return keys.indices.compactMap { index in
            guard valid[index] == 1 else { return nil }
            return ThermalSensorReading(name: keys[index], celsius: values[index])
        }
    }
}
