package service

import (
	"encoding/json"
	"strings"

	"github.com/1Panel-dev/1Panel/agent/utils/common"
)

const (
	vllmAppKeyForUpgrade = "vllm"
	vllmImageEnvKey      = "IMAGE"
	vllmImageTypeNvidia  = "nvidia"
	vllmImageTypeIntel   = "intel"
	vllmImageTypeAscend  = "ascend"
)

func resolveVllmVersionFamily(version, image string) string {
	normalizedVersion := strings.ToLower(strings.TrimSpace(version))
	if strings.HasPrefix(normalizedVersion, vllmImageTypeIntel+"-") {
		return vllmImageTypeIntel
	}
	if strings.HasPrefix(normalizedVersion, vllmImageTypeAscend+"-") {
		return vllmImageTypeAscend
	}
	if strings.HasPrefix(normalizedVersion, vllmImageTypeNvidia+"-") {
		return vllmImageTypeNvidia
	}
	normalizedImage := strings.ToLower(strings.TrimSpace(image))
	if strings.Contains(normalizedImage, "intel/") || strings.Contains(normalizedImage, "llm-scaler-vllm") {
		return vllmImageTypeIntel
	}
	if strings.Contains(normalizedImage, "ascend/") || strings.Contains(normalizedImage, "vllm-ascend") {
		return vllmImageTypeAscend
	}
	return vllmImageTypeNvidia
}

func trimVllmVersionFamily(version string) string {
	trimmed := strings.TrimSpace(version)
	normalized := strings.ToLower(trimmed)
	for _, family := range []string{vllmImageTypeNvidia, vllmImageTypeIntel, vllmImageTypeAscend} {
		prefix := family + "-"
		if strings.HasPrefix(normalized, prefix) {
			return strings.TrimSpace(trimmed[len(prefix):])
		}
	}
	return trimmed
}

func buildDefaultVllmImageByVersion(version string) string {
	tag := trimVllmVersionFamily(version)
	family := resolveVllmVersionFamily(version, "")
	if family == vllmImageTypeIntel {
		return "intel/llm-scaler-vllm:" + tag
	}
	if tag != "" && !strings.HasPrefix(strings.ToLower(tag), "v") {
		tag = "v" + tag
	}
	if family == vllmImageTypeAscend {
		return "quay.io/ascend/vllm-ascend:" + tag
	}
	return "vllm/vllm-openai:" + tag
}

func isVllmUpgradeVersionAllowed(currentVersion, targetVersion, currentImage string) bool {
	currentFamily := resolveVllmVersionFamily(currentVersion, currentImage)
	targetFamily := resolveVllmVersionFamily(targetVersion, "")
	return currentFamily == targetFamily
}

func hasVllmVersionFamilyPrefix(version string) bool {
	normalized := strings.ToLower(strings.TrimSpace(version))
	return strings.HasPrefix(normalized, vllmImageTypeNvidia+"-") ||
		strings.HasPrefix(normalized, vllmImageTypeIntel+"-") ||
		strings.HasPrefix(normalized, vllmImageTypeAscend+"-")
}

func isVllmUpgradeCandidate(currentVersion, targetVersion, currentImage string) bool {
	if strings.TrimSpace(currentVersion) == strings.TrimSpace(targetVersion) {
		return false
	}
	if !isVllmUpgradeVersionAllowed(currentVersion, targetVersion, currentImage) {
		return false
	}
	if common.CompareVersion(targetVersion, currentVersion) {
		return true
	}
	return !hasVllmVersionFamilyPrefix(currentVersion) &&
		resolveVllmVersionFamily(targetVersion, "") == vllmImageTypeNvidia &&
		trimVllmVersionFamily(currentVersion) == trimVllmVersionFamily(targetVersion)
}

func buildVllmUpgradeImage(currentImage, currentVersion, targetVersion string) string {
	trimmedImage := strings.TrimSpace(currentImage)
	if trimmedImage == "" || trimmedImage == buildDefaultVllmImageByVersion(currentVersion) {
		return buildDefaultVllmImageByVersion(targetVersion)
	}
	return trimmedImage
}

func loadVllmImageFromEnv(raw string) string {
	envs := make(map[string]interface{})
	if strings.TrimSpace(raw) == "" {
		return ""
	}
	if err := json.Unmarshal([]byte(raw), &envs); err != nil {
		return ""
	}
	if image, ok := envs[vllmImageEnvKey].(string); ok {
		return strings.TrimSpace(image)
	}
	return ""
}

func setVllmImageInEnvContent(content []byte, image string) []byte {
	normalizedImage := strings.TrimSpace(image)
	if normalizedImage == "" {
		return content
	}
	lines := strings.Split(string(content), "\n")
	replaced := false
	for index, line := range lines {
		if strings.HasPrefix(line, vllmImageEnvKey+"=") {
			lines[index] = vllmImageEnvKey + "=" + normalizedImage
			replaced = true
			break
		}
	}
	if !replaced {
		if len(lines) > 0 && lines[len(lines)-1] == "" {
			lines[len(lines)-1] = vllmImageEnvKey + "=" + normalizedImage
			lines = append(lines, "")
		} else {
			lines = append(lines, vllmImageEnvKey+"="+normalizedImage)
		}
	}
	return []byte(strings.Join(lines, "\n"))
}
