package collector

import (
	"encoding/json"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"
)

func CollectOPNsenseVersion() string {
	out, err := exec.Command("/usr/local/sbin/opnsense-version").Output()
	if err != nil {
		return ""
	}
	// Format: "OPNsense 24.1.1_1" - alles nach erstem Leerzeichen
	s := strings.TrimSpace(string(out))
	return s
}

func CollectFreeBSDVersion() string {
	out, err := exec.Command("/bin/freebsd-version").Output()
	if err != nil {
		return sysctlGet("kern.osrelease")
	}
	return strings.TrimSpace(string(out))
}

func CollectHostname() string {
	return sysctlGet("kern.hostname")
}

func CollectUptime() int64 {
	// kern.boottime: { sec = 1706000000, usec = 0 } ... oder "sec = 1706000000"
	out := sysctlGet("kern.boottime")
	if out == "" {
		return 0
	}

	// Parse "{ sec = TIMESTAMP, usec = ... }"
	idx := strings.Index(out, "sec = ")
	if idx == -1 {
		return 0
	}

	numStr := out[idx+6:]
	if commaIdx := strings.IndexAny(numStr, ", }"); commaIdx != -1 {
		numStr = numStr[:commaIdx]
	}
	numStr = strings.TrimSpace(numStr)

	bootTime, err := strconv.ParseInt(numStr, 10, 64)
	if err != nil {
		return 0
	}

	uptime := time.Now().Unix() - bootTime
	if uptime < 0 {
		return 0
	}
	return uptime
}

// LicenseInfo fuer OPNsense Business Edition
type LicenseInfo struct {
	IsBusinessEdition bool   `json:"is_business_edition"`
	ProductName       string `json:"product_name,omitempty"`
	Subscription      string `json:"subscription,omitempty"`
	ValidTo           string `json:"valid_to,omitempty"`
	DaysRemaining     int    `json:"days_remaining,omitempty"`
}

func CollectLicense() *LicenseInfo {
	// core version file lesen
	coreData, err := os.ReadFile("/usr/local/opnsense/version/core")
	if err != nil {
		return nil
	}

	var core map[string]interface{}
	if err := json.Unmarshal(coreData, &core); err != nil {
		return nil
	}

	productID, _ := core["product_id"].(string)
	coreName, _ := core["CORE_NAME"].(string)

	isBusiness := productID == "opnsense-business" || coreName == "opnsense-business"
	if !isBusiness {
		return &LicenseInfo{IsBusinessEdition: false, ProductName: "OPNsense Community"}
	}

	info := &LicenseInfo{
		IsBusinessEdition: true,
		ProductName:       "OPNsense Business Edition",
	}

	// Lizenz-Ablauf lesen
	licData, err := os.ReadFile("/usr/local/opnsense/version/core.license")
	if err == nil {
		var lic map[string]string
		if json.Unmarshal(licData, &lic) == nil {
			if validTo, ok := lic["valid_to"]; ok {
				info.ValidTo = validTo
				if t, err := time.Parse("2006-01-02", validTo); err == nil {
					days := int(time.Until(t).Hours() / 24)
					info.DaysRemaining = days
				}
			}
		}
	}

	// Subscription-Code aus config.xml lesen
	out, err := exec.Command("/usr/local/bin/php", "-r", `
		$c = simplexml_load_file("/conf/config.xml");
		if (isset($c->system->firmware->subscription)) {
			echo (string)$c->system->firmware->subscription;
		}
	`).Output()
	if err == nil {
		sub := strings.TrimSpace(string(out))
		if sub != "" {
			info.Subscription = sub
		}
	}

	return info
}
