package device

import (
	"context"
	"fmt"
	"strings"

	"git.achmad.dev/admin/droidscope/backend/adb"
)

// FetchInfo retrieves static device information (fetched once on device select).
func FetchInfo(ctx context.Context, client *adb.Client, deviceID string) (*DeviceInfo, error) {
	info := &DeviceInfo{ID: deviceID}

	shell := func(cmd string) string {
		out, _ := client.Shell(ctx, deviceID, cmd)
		return strings.TrimSpace(out)
	}

	info.Manufacturer = shell("getprop ro.product.manufacturer")
	info.Model = shell("getprop ro.product.model")
	info.Product = shell("getprop ro.product.name")
	info.AndroidVersion = shell("getprop ro.build.version.release")
	info.SDKVersion = shell("getprop ro.build.version.sdk")
	info.SecurityPatch = shell("getprop ro.build.version.security_patch")
	info.BuildFingerprint = shell("getprop ro.build.fingerprint")
	info.ABI = shell("getprop ro.product.cpu.abi")
	info.SupportedABIs = shell("getprop ro.product.cpu.abilist")
	info.SerialNumber = shell("getprop ro.serialno")

	info.ScreenResolution = shell("wm size | awk '/Physical/{print $3}'")
	info.ScreenDensity = shell("wm density | awk '/Physical/{print $3}' | tr -d '\\n'")

	info.TotalRAMMB = parseRAM(shell("cat /proc/meminfo | grep MemTotal"))
	info.TotalStorageGB, _ = parseStorage(shell("df /data 2>/dev/null | tail -1"))

	return info, nil
}

// FetchLiveStats retrieves only the fields that change at runtime.
// Called on a 1-second poll interval.
func FetchLiveStats(ctx context.Context, client *adb.Client, deviceID string) (*DeviceLiveStats, error) {
	shell := func(cmd string) string {
		out, _ := client.Shell(ctx, deviceID, cmd)
		return strings.TrimSpace(out)
	}

	stats := &DeviceLiveStats{}

	stats.AvailableRAMMB = parseRAM(shell("cat /proc/meminfo | grep MemAvailable"))

	_, stats.AvailableStorageGB = parseStorage(shell("df /data 2>/dev/null | tail -1"))

	batteryOut := shell("dumpsys battery")
	stats.BatteryLevel = parseBatteryField(batteryOut, "level")
	stats.BatteryStatus = parseBatteryStatusCode(parseBatteryField(batteryOut, "status"))

	stats.ThermalStatus = parseThermalStatus(shell("dumpsys thermalservice 2>/dev/null | grep 'Current thermal status'"))

	ip := shell("ip addr show wlan0 2>/dev/null | grep 'inet ' | awk '{print $2}' | cut -d/ -f1")
	if ip == "" {
		ip = shell("ip route get 8.8.8.8 2>/dev/null | grep src | awk '{print $7}'")
	}
	stats.IPAddress = ip

	return stats, nil
}

func parseRAM(line string) int {
	fields := strings.Fields(line)
	if len(fields) < 2 {
		return 0
	}
	return parseIntSafe(fields[1]) / 1024
}

func parseStorage(dfLine string) (total, available string) {
	fields := strings.Fields(dfLine)
	if len(fields) < 4 {
		return "", ""
	}
	return formatGB(parseIntSafe(fields[1])), formatGB(parseIntSafe(fields[3]))
}

func formatGB(kb int) string {
	if kb == 0 {
		return ""
	}
	gb := float64(kb) / 1024 / 1024
	if gb >= 1 {
		return strings.TrimRight(strings.TrimRight(
			strings.Replace(fmt.Sprintf("%.1f", gb), ".0", "", 1), "0"), ".") + " GB"
	}
	return fmt.Sprintf("%d MB", kb/1024)
}

func parseBatteryField(dumpsys, field string) int {
	for _, line := range strings.Split(dumpsys, "\n") {
		line = strings.TrimSpace(line)
		if strings.HasPrefix(line, field+":") {
			return parseIntSafe(strings.TrimSpace(strings.TrimPrefix(line, field+":")))
		}
	}
	return 0
}

func parseBatteryStatusCode(code int) string {
	switch code {
	case 2:
		return "charging"
	case 3:
		return "discharging"
	case 4:
		return "not charging"
	case 5:
		return "full"
	default:
		return "unknown"
	}
}

func parseThermalStatus(line string) string {
	parts := strings.Split(line, ":")
	if len(parts) < 2 {
		return "none"
	}
	switch parseIntSafe(strings.TrimSpace(parts[1])) {
	case 1:
		return "light"
	case 2:
		return "moderate"
	case 3:
		return "severe"
	case 4:
		return "critical"
	case 5:
		return "emergency"
	case 6:
		return "shutdown"
	default:
		return "none"
	}
}
