#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2019 Michalis Kapsalakis
#

import operator

# The following checks are used in version strings that have the following
# format:
#   For stable: major.minor.patch-build-commit_hash
#   For other: major.minor.patch-pre_release_with_numeric_id-build-commit_hash
#   For unstable, testing: major.minor.patch-pre_release-build-commit-hash
#     alpha:  1.0.0-alpha4-4-ac32f4a
#     beta:   1.0.0-beta1-1-ac32f4b
#     rc:     1.0.0-rc2-2-ac32f4c
#     stable: 1.0.0-1-ac32f4d
#
#
# The different levels define what are the checks that have to sequentially
# executed in order to verify if the new version is applicable for update
#
# Every level has four keys:
#   - comment: it is a comment that explains the level, but it is not used
#   - regex: a list of regular expressions to apply to the full string of the
#            version in order to extract the values that are going to be
#            compared
#   - type: the type of the result of the regex
#   - checks: a list of dictionaries with the checks for the current level
#
#
# Every check has five keys:
#   - comment: it is a comment that explains the check, but it is not used
#   - new: defines what should be the version of the new package
#   - current: defines what should be the version of the current package
#   - operator: defines an operator to do the check between the two versions
#   - result: a boolean variable that defines the result
#
# When "Any" is defined in the new and current keys, an operator is needed in
# order to check the values provided
#
# When a certain value is given to new and current keys, the operator must be
# None. Thus, the algorithm is going to check whether the versions provided
# matches the values of the keys and it returns the result value
#

version_levels = [
    {
        "comment": "First level of checks: strings are equal",
        "regex": [None],
        "type": str,
        "checks": [
            {
                "new": "Any",
                "operator": operator.eq,
                "current": ["Any"],
                "result": False,
                "comment": "Same full version. Not an update",
            },
        ],
    },
    {
        "comment": "Second level of checks: major, minor, and patch",
        "regex": [
            r'^(\d+)\.\d+\.\d+-', r'^\d+\.(\d+)\.\d+-', r'^\d+\.\d+\.(\d+)-'
        ],
        "type": int,
        "checks": [
            {
                "new": "Any",
                "operator": operator.gt,
                "current": ["Any"],
                "result": True,
                "comment": "Greater new major.minor.patch version.",
            },
            {
                "new": "Any",
                "operator": operator.lt,
                "current": ["Any"],
                "result": False,
                "comment": "Lower new major.minor.patch version."
            }
        ],
    },
    {
        "comment": "Third level of checks: stable (None), alpha, beta, rc...",
        "regex": [r'^(?:\d+\.){2}\d+-([a-zA-z]+)\d*-'],
        "type": str,
        "checks": [
            {
                "new": None,
                "operator": None,
                "current": [None],
                "result": False,
                "comment": "Same stable version with different build number."
            },
            {
                "new": None,
                "operator": None,
                "current": ["alpha", "beta", "rc", "testing", "unstable"],
                "result": True,
                "comment": (
                    "stable is always an update above the other versions."
                )
            },
            {
                "new": "alpha",
                "operator": None,
                "current": [None, "beta", "rc", "testing", "unstable"],
                "result": False,
                "comment": (
                    "alpha is not an update over stable, rc or beta." +
                    "For testing and unstable, we don't want to update," +
                    "because the alpha could be an older version than the " +
                    "current installed testing or unstable version."
                )
            },
            {
                "new": "beta",
                "operator": None,
                "current": ["alpha"],
                "result": True,
                "comment": "beta is always an update over alpha."
            },
            {
                "new": "beta",
                "operator": None,
                "current": [None, "rc", "testing", "unstable"],
                "result": False,
                "comment": (
                    "beta is not an update over stable and rc." +
                    "For testing and unstable, we don't want to update," +
                    "because the beta could be an older version than the " +
                    "current installed testing or unstable version."
                )
            },
            {
                "new": "rc",
                "operator": None,
                "current": ["alpha", "beta"],
                "result": True,
                "comment": "rc is always an update over alpha or beta."
            },
            {
                "new": "rc",
                "operator": None,
                "current": [None, "testing", "unstable"],
                "result": False,
                "comment": (
                    "rc is not an update over stable." +
                    "For testing and unstable, we don't want to update," +
                    "because the rc could be an older version than the " +
                    "current installed testing or unstable version."
                )
            },
            {
                "new": "unstable",
                "operator": None,
                "current": [
                    None, "alpha", "beta", "rc", "unstable", "testing"
                ],
                "result": False,
                "comment": "unstable is never an update."
            },
            {
                "new": "testing",
                "operator": None,
                "current": [
                    None, "alpha", "beta", "rc", "unstable", "testing"
                ],
                "result": False,
                "comment": "testing is never an update."
            },
        ]
    },
    {
        "comment": (
            "Fourth level of checks: Checks the pre-release numeric id."
        ),
        "regex": [r'^(?:\d+\.){2}\d+-[a-zA-z]+(\d+)-'],
        "type": int,
        "checks": [
            {
                "new": "Any",
                "operator": operator.gt,
                "current": ["Any"],
                "result": True,
                "comment": "numeric id of new version is greater than the old."
            },
            {
                "new": "Any",
                "operator": operator.lt,
                "current": ["Any"],
                "result": False,
                "comment": "numeric id of new version is lower than the old."
            },
            {
                "new": "Any",
                "operator": operator.eq,
                "current": ["Any"],
                "result": False,
                "comment": "Same stable version with different build number."
            },
        ]
    }
]
