#!/usr/bin/env python

from pickle import FALSE
import sys
import os
import argparse
from mako.template import Template
from mrtutils.mrtTemplateHelper import *
import git
import re
from mrtutils.updates import *
import subprocess
import yaml
import json

args = None
parser = None

#def filter_commits:

th = TemplateHelper()

reIncrement = re.compile(r'\+([0-9]*)')


class VersionStruct:
    def __init__(self):
        self.major = 0
        self.minor = 0
        self.patch = 0
        self.build = 0
        self.branch = "none"
        self.prefix =""
        self.hash = ""
        self.fileName =""
        self.repo = None
        self.fileType = "none"
        self.diffRegexMajor = None
        self.diffRegexMinor = None
        self.diffRegexPatch = None
        self.format="$MAJOR.$MINOR.$PATCH.$BUILD"

        try:
            self.default_branch = subprocess.check_output(['git remote show', self.path ,"| sed -n '/HEAD branch/s/.*: //p'", '-f'])
        except:
            self.default_branch = 'main'

    def setPrefix(self, prefix):
        if not prefix == "":
            self.prefix = prefix+"_"

    def loadFile(self,path):
        base_name, extension = os.path.splitext(path)

        #This covers the case of files like '.env'
        if base_name[0] == '.' and extension == '':
            extension = base_name

        self.fileType = extension.replace(".","")

        if os.path.exists(path):

            if self.fileType == "h":
                self.loadCFile(path)

            elif self.fileType == "yml" or self.fileType == "yaml":
                self.loadYamlFile(path)

            elif self.fileType == "json":
                self.loadJsonFile(path)
            elif self.fileType == "env":
                self.loadEnvFile(path)
            else :
                print("Unsupported File type: " + self.fileType)

    def loadEnvFile(self,path):
        self.diffRegexMajor = re.compile(r'\+.*?VERSION_MAJOR=(\S*?)\s*?\n' )
        self.diffRegexMinor = re.compile(r'\+.*?VERSION_MINOR=(\S*?)\s*?\n' )
        self.diffRegexPatch = re.compile(r'\+.*?VERSION_PATCH=(\S*?)\s*?\n' )

        f = open(path)
        txt = f.read()
        self.fileName = path
        
        reMajor = re.compile(r'VERSION_MAJOR=(\S*?)\s*?\n' )
        reMinor = re.compile(r'VERSION_MINOR=(\S*?)\s*?\n' )
        rePatch = re.compile(r'VERSION_PATCH=(\S*?)\s*?\n' )
        reBuild = re.compile(r'VERSION_BUILD=(\S*?)\s*?\n' )
        
        mMajor = reMajor.findall(txt)
        mMinor = reMinor.findall(txt)

        mPatch = rePatch.findall(txt)
        mBuild = reBuild.findall(txt)

        self.major = int(mMajor[0].strip())
        self.minor = int(mMinor[0].strip())
        self.patch = int(mPatch[0].strip())
        self.build = int(mBuild[0].strip())

    def loadYamlFile(self,path):

        self.diffRegexMajor = re.compile(r'\+.*?major\s*?(\S*?)\s*?\n' )
        self.diffRegexMinor = re.compile(r'\+.*?minor\s*?(\S*?)\s*?\n' )
        self.diffRegexPatch = re.compile(r'\+.*?patch\s*?(\S*?)\s*?\n' )

        f = open(path)
        txt = f.read()
        dict = yaml.load(txt, Loader=yaml.FullLoader)

        self.major = dict[self.prefix+'major']
        self.minor = dict[self.prefix+'minor']
        self.patch = dict[self.prefix+'patch']
        self.build = dict[self.prefix+'build']

    def loadJsonFile(self,path):

        self.diffRegexMajor = re.compile(r'\+.*?major\s*?(\S*?)\s*?\n' )
        self.diffRegexMinor = re.compile(r'\+.*?minor\s*?(\S*?)\s*?\n' )
        self.diffRegexPatch = re.compile(r'\+.*?patch\s*?(\S*?)\s*?\n' )
    
        f = open(path)
        txt = f.read()
        dict = json.loads(txt)

        self.major = dict[self.prefix+'major']
        self.minor = dict[self.prefix+'minor']
        self.patch = dict[self.prefix+'patch']
        self.build = dict[self.prefix+'build']

        pass

    def loadCFile(self, path):

        self.diffRegexMajor = re.compile(r'\+.*?VERSION_MAJOR\s*?(\S*?)\s*?\n' )
        self.diffRegexMinor = re.compile(r'\+.*?VERSION_MINOR\s*?(\S*?)\s*?\n' )
        self.diffRegexPatch = re.compile(r'\+.*?VERSION_PATCH\s*?(\S*?)\s*?\n' )

        f = open(path)
        txt = f.read()
        self.fileName = path
        
        reMajor = re.compile(r'VERSION_MAJOR\s*?(\S*?)\s*?\n' )
        reMinor = re.compile(r'VERSION_MINOR\s*?(\S*?)\s*?\n' )
        rePatch = re.compile(r'VERSION_PATCH\s*?(\S*?)\s*?\n' )
        reBuild = re.compile(r'VERSION_BUILD\s*?(\S*?)\s*?\n' )
        
        mMajor = reMajor.findall(txt)
        mMinor = reMinor.findall(txt)

        mPatch = rePatch.findall(txt)
        mBuild = reBuild.findall(txt)

        self.major = int(mMajor[0].strip())
        self.minor = int(mMinor[0].strip())
        self.patch = int(mPatch[0].strip())
        self.build = int(mBuild[0].strip())
        
    
    def loadRepo(self,repo):

        self.repo = repo

        try: 
            self.branch = repo.active_branch.name
        except:
            self.branch = 'DETACHED_' + repo.head.object.hexsha
            print("Repo in Detached head state")
            
        self.hash = repo.head.commit.hexsha



    def setMajor(self, str):

        increment = reIncrement.findall(str)

        if len(increment) > 0:
            val = int(increment[0])
            self.major += val 
            self.minor = 0
            self.patch = 0
        
        else:
            self.major = int(str)

    def setMinor(self, str):
        
        increment = reIncrement.findall(str)

        if str.isnumeric():
            self.minor = int(str)
            return

        if str.startswith('auto'):
            self.minor = self.getCommitsSinceLast(self.default_branch, change='major')
            self.patch = 0
        if len(increment) > 0: 
            val = int(increment[0])
            self.minor += val 
            self.patch = 0

    def setPatch(self, str):

        increment = reIncrement.findall(str)

        if str.isnumeric():
            self.patch = int(str)
            return

        if str.startswith('auto'):
            self.patch = self.getCommitsSinceLast(self.default_branch, change='minor')
        
        if len(increment) > 0: 
            val = int(increment[0])
            self.patch += val   


    def setBuild(self, str):
         
        increment = reIncrement.findall(str)

        if str.isnumeric():
            self.build = int(str)
            return

        if str.startswith('auto'):
            self.build = self.getCommitsSinceLast(self.default_branch, change='patch')
        
        if len(increment) > 0: 
            val = int(increment[0])
            self.build += val   

    def getCommitsSinceLast(self, branch = 'master', change= 'minor' ):
    
        repattern = None
        count = 1

        if change == 'minor':
            repattern = self.diffRegexMinor
        if change == 'major':
            repattern = self.diffRegexMajor
        elif change == 'patch':
            repattern = self.diffRegexPatch
        
        commit = self.repo.commit(branch)
        firstParent = None 

        #iterate through using first-parent method 
        while(len(commit.parents) > 0):
            firstParent = commit.parents[0]

            try:
                diff = self.repo.git.diff(firstParent, commit, self.fileName)
            except:
                return 0

            if repattern.search(diff):
                    return count
            
            count+= 1
            commit = firstParent

        
        return 0


    def asString(self):

        out = self.format
        out = out.replace("$MAJOR", str(self.major))
        out = out.replace("$MINOR", str(self.minor))
        out = out.replace("$PATCH", str(self.patch))
        out = out.replace("$BUILD", str(self.build))
        out = out.replace("$BRANCH", self.branch)
        out = out.replace("$HASH", self.hash)

        return out




  

# Initialize the argument parser
def init_args():
    global parser
    parser = argparse.ArgumentParser("Tool to generate version file")
    parser.add_argument('versionFile', type=str, nargs='?', help='version header file', default="version.h")
    parser.add_argument('-n', '--namespace', type=str, help='namespace to set prefix', default="")
    parser.add_argument('-M', '--major', type=str, help='Major version', default="")
    parser.add_argument('-m', '--minor', type=str, help='Minor version', default="")
    parser.add_argument('-p', '--patch', type=str, help='Patch', default="")
    parser.add_argument('-b', '--build', type=str, help='build number', default="")
    parser.add_argument('-f', '--format', type=str, help='Output format', default="$MAJOR.$MINOR.$PATCH")

    

def main():
    global parser
    global args
    init_args()
    args = parser.parse_args() 
    vs = VersionStruct()
    th = TemplateHelper()


    repo = git.Repo(os.getcwd())
    vs.loadRepo(repo)
    vs.format = args.format
    vs.setPrefix(args.namespace)
    
    vs.loadFile(args.versionFile)

    if not args.major == "":
        vs.setMajor(args.major)
    if not args.minor == "":
        vs.setMinor(args.minor)
    if not args.patch == "":
        vs.setPatch(args.patch)
    if not args.build == "":
        vs.setBuild(args.build)

    th.buildTemplate(vs, "templates/version/version." + vs.fileType , args.versionFile)



    print(vs.asString())



if __name__ == "__main__":
    main()