//
//  Version.swift
//  InstanceFeatures
//
//  Created by Shadowfacts on 5/14/23.
//

import Foundation

@_spi(InstanceType) public struct Version: Equatable, Comparable, CustomStringConvertible {
    private static let regex = try! NSRegularExpression(pattern: "^(\\d+)\\.(\\d+)\\.(\\d+).*$")
    
    let major: Int
    let minor: Int
    let patch: Int
    
    init(_ major: Int, _ minor: Int, _ patch: Int) {
        self.major = major
        self.minor = minor
        self.patch = patch
    }
    
    init?(string: String) {
        guard let match = Version.regex.firstMatch(in: string, range: NSRange(location: 0, length: string.utf16.count)),
              match.numberOfRanges == 4 else {
            return nil
        }
        let majorStr = (string as NSString).substring(with: match.range(at: 1))
        let minorStr = (string as NSString).substring(with: match.range(at: 2))
        let patchStr = (string as NSString).substring(with: match.range(at: 3))
        guard let major = Int(majorStr),
              let minor = Int(minorStr),
              let patch = Int(patchStr) else {
            return nil
        }
        self.major = major
        self.minor = minor
        self.patch = patch
    }
    
    public var description: String {
        "\(major).\(minor).\(patch)"
    }
    
    public static func ==(lhs: Version, rhs: Version) -> Bool {
        return lhs.major == rhs.major && lhs.minor == rhs.minor && lhs.patch == rhs.patch
    }
    
    public static func <(lhs: Version, rhs: Version) -> Bool {
        if lhs.major < rhs.major {
            return true
        } else if lhs.major > rhs.major {
            return false
        } else if lhs.minor < rhs.minor {
            return true
        } else if lhs.minor > rhs.minor {
            return false
        } else if lhs.patch < rhs.patch {
            return true
        } else {
            return false
        }
    }
}

func <(lhs: Version?, rhs: Version) -> Bool {
    guard let lhs else {
        // nil is less than or equal to everything
        return true
    }
    return lhs < rhs
}
    
func >=(lhs: Version?, rhs: Version) -> Bool {
    guard let lhs else {
        // nil is less than or equal to everything
        return false
    }
    return lhs >= rhs
}
