"""
version.py version information manager
Author: Shai Bennathan - shai.bennathan@gmail.com
(C) 2020
"""
import logging
import datetime
from os import path
from re import findall
from pykrete.io.file import write_lines
from .version import Version
from .revision_type import RevisionType
from .formatting import Formatting


def make_python_root_version_file_path(project):
    """ Generate the version.py file from the project's name

    :param project: project name
    :return: src/<project>/version.py
    """
    return path.join('src', project, 'version.py')


class VersionPyVersion(Version):
    """Handle version in python.py"""

    revisions = {
        '.': RevisionType.Release,
        'rc': RevisionType.RC,
        'b': RevisionType.Beta,
        'a': RevisionType.Alpha}

    def __init__(self, project, set_version=None):
        """Initialize this instance from the specified project's version.py file

        :param project: Python project (under 'src')
        :param set_version: Optional version to set instead of the one in the file (defaults to
         None, which means read the version from the file)
        """
        self._logger = logging.getLogger(__name__)
        self._project = project.title()
        self._version_py_path = make_python_root_version_file_path(project)
        if set_version:
            super().__init__(set_version)
        else:
            version_match = self.__read_version_match()
            version_parts = self.__parse_version_parts(version_match)
            super().__init__(version_parts)
        self._logger.debug('%s version.py version is %s', self._project, self)

    def apply(self):
        """Apply this version to the relevant environment
        """
        with open(self._version_py_path, 'w') as file:
            write_lines(file, self.__make_version_file_lines())
        self._logger.debug('Set %s version.py version to %s', self._project, self)

    def __read_version_match(self):
        try:
            with open(self._version_py_path, 'r') as file:
                separator_pattern = '|'.join(VersionPyVersion.revisions.keys()).replace('.', r'\.')
                return findall(f"__version__ = '(\\d+)\\.(\\d+)({separator_pattern})(\\d+)'",
                               file.read())[0]
        except IndexError:
            raise IOError("No version specification found in file")

    def __make_version_file_lines(self):
        """Makes the lines of version.py

        :return: The version file's lines
        """
        return [
            '"""',
            f'{self._project} module version',
            'AUTO-GENERATED BY BUILD SCRIPT',
            f'(C) {datetime.date.today().year}',
            '"""',
            '',
            f'__version__ = \'{Formatting(self).for_python}\'',
            ''
        ]

    @staticmethod
    def __parse_version_parts(version_parts):
        if not version_parts or len(version_parts) != 4:
            raise IOError('Incompatible version')
        revision_marker = version_parts[2]
        revision_type = VersionPyVersion.revisions[revision_marker]
        return (version_parts[0], version_parts[1], revision_type.value, version_parts[3],
                revision_type)
