package main

import (
	"encoding/json"
	"fmt"
	"syscall"
	"time"
	"unsafe"

	"golang.org/x/sys/windows"
)

const (
	sharedMemoryName = "AIDA64_SensorValues"
	sensorValueSize  = 64 + 64 + 8 // 32 bytes id + 64 bytes label + 8 bytes float64 value (padding kaldırıldı)
	maxSensors       = 128
	refreshInterval  = 500 * time.Millisecond
)

type Sensor struct {
	ID    string  `json:"id"`
	Label string  `json:"label"`
	Value float64 `json:"value"`
}

// kernel32.dll'den OpenFileMappingW fonksiyonunu çağırmak için
var (
	modkernel32         = syscall.NewLazyDLL("kernel32.dll")
	procOpenFileMapping = modkernel32.NewProc("OpenFileMappingW")
)

func OpenFileMapping(desiredAccess uint32, inheritHandle bool, name *uint16) (handle windows.Handle, err error) {
	var inherit uint32
	if inheritHandle {
		inherit = 1
	} else {
		inherit = 0
	}

	r0, _, e1 := procOpenFileMapping.Call(
		uintptr(desiredAccess),
		uintptr(inherit),
		uintptr(unsafe.Pointer(name)),
	)
	handle = windows.Handle(r0)
	if handle == 0 {
		if e1 != nil {
			err = error(e1)
		} else {
			err = syscall.EINVAL
		}
	}
	return
}

func main() {
	go readSensorsLoop()
	select {} // Sonsuza kadar bekle
}

func readSensorsLoop() {
	namePtr, _ := windows.UTF16PtrFromString(sharedMemoryName)

	handle, err := OpenFileMapping(windows.FILE_MAP_READ, false, namePtr)
	if err != nil {
		panic("AIDA64 paylaşılan belleği açılamadı: " + err.Error())
	}
	defer windows.CloseHandle(handle)

	size := uintptr(sensorValueSize * maxSensors)
	addr, err := windows.MapViewOfFile(handle, windows.FILE_MAP_READ, 0, 0, size)
	if err != nil {
		panic("MapViewOfFile başarısız: " + err.Error())
	}
	defer windows.UnmapViewOfFile(addr)

	for {
		sensors := readSensors(addr)
		jsonOutput, _ := json.MarshalIndent(sensors, "", "  ")
		fmt.Println(string(jsonOutput))
		time.Sleep(refreshInterval)
	}
}

func readSensors(baseAddr uintptr) []Sensor {
	sensors := []Sensor{}

	for i := 0; i < maxSensors; i++ {
		offset := baseAddr + uintptr(i*sensorValueSize)

		rawID := (*[32]byte)(unsafe.Pointer(offset))[:]
		rawLabel := (*[64]byte)(unsafe.Pointer(offset + 32))[:]
		rawValuePtr := unsafe.Pointer(offset + 32 + 64)

		id := cleanString(rawID)
		label := cleanString(rawLabel)
		value := *(*float64)(rawValuePtr)

		// Değerler normal değilse (çok büyük/çok küçük) sensörü atla
		if value > 1e10 || value < -1e10 || value != value { // value != value -> NaN kontrolü
			continue
		}
		if id == "" && label == "" {
			continue
		}

		id = cleanXMLTags(id)
		label = cleanXMLTags(label)

		sensors = append(sensors, Sensor{
			ID:    id,
			Label: label,
			Value: value,
		})
	}

	return sensors
}

func cleanString(b []byte) string {
	for i, c := range b {
		if c == 0 {
			return string(b[:i])
		}
	}
	return string(b)
}

func readCString(b []byte) string {
	for i, c := range b {
		if c == 0 {
			return string(b[:i])
		}
	}
	return string(b)
}

func cleanXMLTags(s string) string {
	// Basit XML/HTML etiketlerini temizle
	result := ""
	inTag := false
	for _, r := range s {
		if r == '<' {
			inTag = true
			continue
		}
		if r == '>' {
			inTag = false
			continue
		}
		if !inTag {
			result += string(r)
		}
	}
	return result
}
