using System;
using UnityEngine;

namespace pdinklag
{
    [Serializable]
    public readonly struct SemanticVersion
    {
        public static readonly SemanticVersion ZERO = new(0, 0, 0);

        public static bool TryParse(string s, out SemanticVersion version)
        {
            if (s != null)
            {
                var v = s.Split('.');
                if (v.Length == 3 && uint.TryParse(v[0], out var major) && uint.TryParse(v[1], out var minor) && uint.TryParse(v[2], out var patch))
                {
                    version = new(major, minor, patch);
                    return true;
                }
            }
            version = ZERO;
            return false;
        }

        public static SemanticVersion Parse(string s) => TryParse(s, out var v) ? v : ZERO;

        public static bool operator ==(SemanticVersion a, SemanticVersion b) => a.Major == b.Major && a.Minor == b.Minor && a.Patch == b.Patch;
        public static bool operator !=(SemanticVersion a, SemanticVersion b) => !(a == b);

        public static bool operator <(SemanticVersion a, SemanticVersion b)
        {
            if (a.Major < b.Major)
            {
                return true;
            }
            else if (a.Major == b.Major)
            {
                if (a.Minor < b.Minor)
                {
                    return true;
                }
                else if (a.Minor == b.Minor)
                {
                    return a.Patch < b.Patch;
                }
            }
            return false;
        }

        public static bool operator >(SemanticVersion a, SemanticVersion b)
        {
            if (a.Major > b.Major)
            {
                return true;
            }
            else if (a.Major == b.Major)
            {
                if (a.Minor > b.Minor)
                {
                    return true;
                }
                else if (a.Minor == b.Minor)
                {
                    return a.Patch > b.Patch;
                }
            }
            return false;
        }

        public static bool operator <=(SemanticVersion a, SemanticVersion b) => (a == b) || (a < b);
        public static bool operator >=(SemanticVersion a, SemanticVersion b) => (a == b) || (a > b);

        public static SemanticVersion Current => Parse(Application.version);

        public readonly uint Major;
        public readonly uint Minor;
        public readonly uint Patch;

        public bool IsZero => Major == 0 && Minor == 0 && Patch == 0;
        public bool IsNonZero => Major != 0 || Minor != 0 || Patch != 0;

        public SemanticVersion(uint major, uint minor, uint patch)
        {
            Major = major;
            Minor = minor;
            Patch = patch;
        }

        public override bool Equals(object obj) => obj is SemanticVersion v && v == this;
        public override int GetHashCode() => 17 + 31 * Major.GetHashCode() + 31 * Minor.GetHashCode() + 31 * Patch.GetHashCode();

        public override string ToString() => string.Format("{0}.{1}.{2}", Major, Minor, Patch);
    }
}
