package handlers

import (
	"net"
	"os"
	"os/user"
	"runtime"

	"github.com/shirou/gopsutil/v3/cpu"
	"github.com/shirou/gopsutil/v3/disk"
	"github.com/shirou/gopsutil/v3/host"
	"github.com/shirou/gopsutil/v3/mem"
)

// Ajan versiyonu
const AjanVersiyon = "3.0.0"

// SistemHandler - Sistem bilgisi işleyici
type SistemHandler struct{}

// YeniSistemHandler - Yeni sistem handler
func YeniSistemHandler() *SistemHandler {
	return &SistemHandler{}
}

// SistemBilgisi - Sistem bilgisi yapısı
type SistemBilgisi struct {
	// Statik cihaz bilgileri (değişmez)
	Hostname     string   `json:"hostname"`
	OS           string   `json:"os"`
	OsVersiyon   string   `json:"osVersiyon"`
	Platform     string   `json:"platform"`
	Mimari       string   `json:"mimari"`
	CPUModel     string   `json:"cpuModel"`
	CPUCekirdek  int      `json:"cpuCekirdek"`
	RAMToplam    uint64   `json:"ramToplam"`
	DiskToplam   uint64   `json:"diskToplam"`
	Kullanici    string   `json:"kullanici"`
	MacAdresi    string   `json:"macAdresi"`
	IpAdresleri  []string `json:"ipAdresleri"`
	AjanVersiyon string   `json:"ajanVersiyon"`

	// Dinamik bilgiler (değişir)
	CPUKullanim float64     `json:"cpuKullanim"`
	RAMKullanan uint64      `json:"ramKullanan"`
	RAMYuzde    float64     `json:"ramYuzde"`
	DiskBilgi   []DiskBilgi `json:"diskBilgi"`
	DiskYuzde   float64     `json:"diskYuzde"`
	Uptime      uint64      `json:"uptime"`
}

// DiskBilgi - Disk bilgisi
type DiskBilgi struct {
	MountPoint string  `json:"mountPoint"`
	Toplam     uint64  `json:"toplam"`
	Kullanan   uint64  `json:"kullanan"`
	Bos        uint64  `json:"bos"`
	Yuzde      float64 `json:"yuzde"`
}

// BilgiTopla - Sistem bilgilerini topla
func (sh *SistemHandler) BilgiTopla() (*SistemBilgisi, error) {
	bilgi := &SistemBilgisi{}

	// Ajan versiyonu
	bilgi.AjanVersiyon = AjanVersiyon

	// Hostname
	hostname, _ := os.Hostname()
	bilgi.Hostname = hostname

	// OS bilgisi
	hostInfo, _ := host.Info()
	if hostInfo != nil {
		bilgi.OS = hostInfo.OS
		bilgi.OsVersiyon = hostInfo.PlatformVersion
		bilgi.Platform = hostInfo.Platform
		bilgi.Uptime = hostInfo.Uptime
	}

	// Mimari (Architecture)
	bilgi.Mimari = runtime.GOARCH

	// Kullanıcı bilgisi
	currentUser, err := user.Current()
	if err == nil {
		bilgi.Kullanici = currentUser.Username
	}

	// CPU bilgisi
	cpuInfo, _ := cpu.Info()
	if len(cpuInfo) > 0 {
		bilgi.CPUModel = cpuInfo[0].ModelName
	}
	bilgi.CPUCekirdek = runtime.NumCPU()

	// CPU kullanım
	cpuPercent, _ := cpu.Percent(0, false)
	if len(cpuPercent) > 0 {
		bilgi.CPUKullanim = cpuPercent[0]
	}

	// RAM bilgisi
	memInfo, _ := mem.VirtualMemory()
	if memInfo != nil {
		bilgi.RAMToplam = memInfo.Total
		bilgi.RAMKullanan = memInfo.Used
		bilgi.RAMYuzde = memInfo.UsedPercent
	}

	// Network bilgisi (MAC ve IP)
	bilgi.IpAdresleri = []string{}
	interfaces, _ := net.Interfaces()
	for _, iface := range interfaces {
		// Loopback ve down olan interfaceleri atla
		if iface.Flags&net.FlagLoopback != 0 || iface.Flags&net.FlagUp == 0 {
			continue
		}

		// İlk geçerli MAC adresini al
		if bilgi.MacAdresi == "" && iface.HardwareAddr != nil && len(iface.HardwareAddr) > 0 {
			bilgi.MacAdresi = iface.HardwareAddr.String()
		}

		// IP adreslerini topla
		addrs, _ := iface.Addrs()
		for _, addr := range addrs {
			if ipNet, ok := addr.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
				if ipNet.IP.To4() != nil {
					bilgi.IpAdresleri = append(bilgi.IpAdresleri, ipNet.IP.String())
				}
			}
		}
	}

	// Disk bilgisi
	var toplamDisk uint64 = 0
	var kullanilanDisk uint64 = 0
	partitions, _ := disk.Partitions(false)
	for _, p := range partitions {
		usage, err := disk.Usage(p.Mountpoint)
		if err != nil {
			continue
		}

		diskBilgi := DiskBilgi{
			MountPoint: p.Mountpoint,
			Toplam:     usage.Total,
			Kullanan:   usage.Used,
			Bos:        usage.Free,
			Yuzde:      usage.UsedPercent,
		}
		bilgi.DiskBilgi = append(bilgi.DiskBilgi, diskBilgi)
		toplamDisk += usage.Total
		kullanilanDisk += usage.Used
	}
	bilgi.DiskToplam = toplamDisk
	if toplamDisk > 0 {
		bilgi.DiskYuzde = float64(kullanilanDisk) / float64(toplamDisk) * 100
	}

	return bilgi, nil
}

// HizliBilgi - Sadece CPU ve RAM (periyodik güncelleme için)
func (sh *SistemHandler) HizliBilgi() map[string]interface{} {
	bilgi := make(map[string]interface{})

	// CPU kullanım
	cpuPercent, _ := cpu.Percent(0, false)
	if len(cpuPercent) > 0 {
		bilgi["cpuKullanim"] = cpuPercent[0]
	}

	// RAM bilgisi
	memInfo, _ := mem.VirtualMemory()
	if memInfo != nil {
		bilgi["ramYuzde"] = memInfo.UsedPercent
		bilgi["ramKullanan"] = memInfo.Used
	}

	return bilgi
}
