// Author: NiuJiuRu
// Email: niujiuru@qq.com

package baseapp

import (
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

// 用32位无符号整数表示版本号, 组成格式:
// [major(8bit)][minor(8bit)][patch(8bit)][build(8bit)]
// 对应的字符串组成格式必须为: "x.y.z.w"
type VersionCode uint32

func NewVersionCode(major, minor, patch, build uint32) VersionCode {
	return VersionCode(major<<24 | minor<<16 | patch<<8 | build)
}

func (v *VersionCode) FromString(s string) error {
	parts := strings.Split(s, ".")
	if len(parts) != 4 {
		return fmt.Errorf("invalid version string: %s", s)
	}

	var u uint32
	for i, p := range parts {
		n, err := strconv.Atoi(p)
		if err != nil || n < 0 || n > 255 {
			return fmt.Errorf("invalid version part: %s", p)
		}
		u |= uint32(n) << uint((3-i)*8)
	}
	*v = VersionCode(u)
	return nil
}

func (v VersionCode) String() string {
	return fmt.Sprintf("%d.%d.%d.%d", v.Major(), v.Minor(), v.Patch(), v.Build())
}

func (v VersionCode) Parts() [4]uint32 {
	shifts := [4]uint{24, 16, 8, 0}
	var parts [4]uint32
	for i, s := range shifts {
		parts[i] = uint32(v>>s) & 0xFF
	}
	return parts
}

func (v VersionCode) Major() uint32 { return v.Parts()[0] }
func (v VersionCode) Minor() uint32 { return v.Parts()[1] }
func (v VersionCode) Patch() uint32 { return v.Parts()[2] }
func (v VersionCode) Build() uint32 { return v.Parts()[3] }

func WriteVersionFile(dir, version string) error {
	file := filepath.Join(dir, "version.txt")
	tmp := file + ".tmp"

	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}

	if err := os.WriteFile(tmp, []byte(version+"\n"), 0644); err != nil {
		return err
	}

	return os.Rename(tmp, file)
}
