package version

import (
	"context"
	"strconv"
	"strings"

	"github.com/xtls/xray-core/common"
	"github.com/xtls/xray-core/common/errors"
)

type Version struct {
	config *Config
	ctx    context.Context
}

func New(ctx context.Context, config *Config) (*Version, error) {
	if config.MinVersion != "" {
		result, err := compareVersions(config.MinVersion, config.CoreVersion)
		if err != nil {
			return nil, err
		}
		if result > 0 {
			return nil, errors.New("this config must be run on version ", config.MinVersion, " or higher")
		}
	}
	if config.MaxVersion != "" {
		result, err := compareVersions(config.MaxVersion, config.CoreVersion)
		if err != nil {
			return nil, err
		}
		if result < 0 {
			return nil, errors.New("this config should be run on version ", config.MaxVersion, " or lower")
		}
	}
	return &Version{config: config, ctx: ctx}, nil
}

func compareVersions(v1, v2 string) (int, error) {
	// Split version strings into components
	v1Parts := strings.Split(v1, ".")
	v2Parts := strings.Split(v2, ".")

	// Pad shorter versions with zeros
	for len(v1Parts) < len(v2Parts) {
		v1Parts = append(v1Parts, "0")
	}
	for len(v2Parts) < len(v1Parts) {
		v2Parts = append(v2Parts, "0")
	}

	// Compare each part
	for i := 0; i < len(v1Parts); i++ {
		// Convert parts to integers
		n1, err := strconv.Atoi(v1Parts[i])
		if err != nil {
			return 0, errors.New("invalid version component ", v1Parts[i], " in ", v1)
		}
		n2, err := strconv.Atoi(v2Parts[i])
		if err != nil {
			return 0, errors.New("invalid version component ", v2Parts[i], " in ", v2)
		}

		if n1 < n2 {
			return -1, nil // v1 < v2
		}
		if n1 > n2 {
			return 1, nil // v1 > v2
		}
	}
	return 0, nil // v1 == v2
}

func init() {
	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
		return New(ctx, config.(*Config))
	}))
}
