// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package arch

import (
	"strconv"
	"strings"
	"unicode"
)

// https://gitlab.archlinux.org/pacman/pacman/-/blob/d55b47e5512808b67bc944feb20c2bcc6c1a4c45/lib/libalpm/version.c

func parseEVR(evr string) (epoch, version, release string) {
	if before, after, f := strings.Cut(evr, ":"); f {
		epoch = before
		evr = after
	} else {
		epoch = "0"
	}

	if before, after, f := strings.Cut(evr, "-"); f {
		version = before
		release = after
	} else {
		version = evr
		release = "1"
	}
	return epoch, version, release
}

func compareSegments(a, b []string) int {
	lenA, lenB := len(a), len(b)
	l := min(lenA, lenB)
	for i := range l {
		if r := compare(a[i], b[i]); r != 0 {
			return r
		}
	}
	if lenA == lenB {
		return 0
	} else if l == lenA {
		return -1
	}
	return 1
}

func compare(a, b string) int {
	if a == b {
		return 0
	}

	aNumeric := isNumeric(a)
	bNumeric := isNumeric(b)

	if aNumeric && bNumeric {
		aInt, _ := strconv.Atoi(a)
		bInt, _ := strconv.Atoi(b)
		switch {
		case aInt < bInt:
			return -1
		case aInt > bInt:
			return 1
		default:
			return 0
		}
	}

	if aNumeric {
		return 1
	}
	if bNumeric {
		return -1
	}

	return strings.Compare(a, b)
}

func isNumeric(s string) bool {
	for _, c := range s {
		if !unicode.IsDigit(c) {
			return false
		}
	}
	return true
}

func compareVersions(a, b string) int {
	if a == b {
		return 0
	}

	epochA, versionA, releaseA := parseEVR(a)
	epochB, versionB, releaseB := parseEVR(b)

	if res := compareSegments([]string{epochA}, []string{epochB}); res != 0 {
		return res
	}

	if res := compareSegments(strings.Split(versionA, "."), strings.Split(versionB, ".")); res != 0 {
		return res
	}

	return compareSegments([]string{releaseA}, []string{releaseB})
}
