from git import Repo
import datetime
import os
import re
from typing import Tuple
import sys

REDCOLOR = "\033[1;31m"
GREENCOLOR = "\033[1;32m"
YELLOWCOLOR = "\033[1;33m"
BLUECOLOR = "\033[1;34m"
RESETCOLOR = "\033[0m"

HEADER_PATTERN = re.compile(r"^.*\*{71}.*$(?:\n.*)*?^.*\*{71}.*\n", re.MULTILINE)


def get_source_dir(envVar):
    sd = os.environ.get(envVar, None)
    if sd is None:
        print(f"{REDCOLOR}ERROR! Enviromental variable {envVar} is not set. Perhapse you forgot to set it in your shell profile?{RESETCOLOR}")
        exit(1)
    return sd

def get_git_log(repoPath, filePath):
    """
    Retrieves the git commit history for a specific file.
    
    :param repoPath: Path to the Git repository
    :param filePath: Path to the file relative to the repo root
    :return: List of commit messages with commit hashes
    """
    repo = Repo(repoPath)
    commits = list(repo.iter_commits(paths=filePath))  # Get commits affecting the file
    
    logEntries = []
    for commit in commits:
        logEntries.append(f"{commit.hexsha[:7]} - {commit.author.name} - {commit.committed_date}")

    return logEntries

def get_all_file_authors(logEntries):
    """
    Retrieves the authors of the commits in a list of log entries.
    
    :param logEntries: List of log entries
    :return: List of authors
    """
    authors = []
    for entry in logEntries:
        authors.append(entry.split(" - ")[1])
    return set(authors)

def get_last_modification_date(logEntries):
    """
    Retrieves the last modification date of the file.
    
    :param logEntries: List of log entries
    :return: Last modification date
    """
    return datetime.datetime.fromtimestamp(int(logEntries[0].split(" - ")[2]))

def select_comment_chars(filename) -> Tuple[str, str, str]:
    fileExtension = filename.split(".")[-1]
    #switch statement based on file extension
    match fileExtension:
        case "py":
            return ("\"\"\"", "\"\"\"", "#")
        case "c" | "cpp" | "h" | "hpp":
            return ("/*", "*/", "//")
        case "f90" | "f":
            return ("!", "!", "!")
        case "sh":
            return ("#", "#", "#")
        case "cmake":
            return ("#", "#", "#")
        case "build":
            return ("#", "#", "#")
        case _:
            return ("#", "", "#")

def make_header(authors, date, filename, projectName):
    authorSuffix = "s" if len(authors) > 1 else ""
    authorsString = ', '.join(authors)
    bs, be, c = select_comment_chars(filename)

    defaultHeader = f"""{bs} ***********************************************************************
{c}
{c}   Copyright (C) {date.year} -- The 4D-STAR Collaboration
{c}   File Author{authorSuffix}: {authorsString}
{c}   Last Modified: {date.date().strftime("%B %d, %Y")}
{c}
{c}   {projectName} is free software; you can use it and/or modify
{c}   it under the terms and restrictions the GNU General Library Public
{c}   License version 3 (GPLv3) as published by the Free Software Foundation.
{c}
{c}   {projectName} is distributed in the hope that it will be useful,
{c}   but WITHOUT ANY WARRANTY; without even the implied warranty of
{c}   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
{c}   See the GNU Library General Public License for more details.
{c}
{c}   You should have received a copy of the GNU Library General Public License
{c}   along with this software; if not, write to the Free Software
{c}   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{c}
{c} *********************************************************************** {be}\n"""

    return defaultHeader

if __name__ == "__main__":
    # Ensure python version at least 3.10
    if sys.version_info < (3, 10):
        print(f"{REDCOLOR}ERROR! Python version 3.10 or higher is required{RESETCOLOR}")

    import argparse

    parser = argparse.ArgumentParser(description="Format the header of a file")
    parser.add_argument("file", type=str, help="The file to format")
    parser.add_argument("--root", type=str, default="_4DSSE_ROOT", help="The name of the environmental variable that points to the root of the project")
    parser.add_argument("--project", type=str, default="4DSSE", help="The name of the project")
    args = parser.parse_args()

    absPath = os.path.abspath(args.file)
    fileName = os.path.basename(args.file)
    if fileName == "formatHeader.py":
        print(f"{BLUECOLOR}NOTE! Cannot format the formatHeader script{RESETCOLOR}")
        exit(0)

    assert os.path.exists(absPath), f"{REDCOLOR}ERROR! The file {absPath} does not exist{RESETCOLOR}"

    sd = get_source_dir(args.root)
    if not absPath.startswith(sd):
        print(f"{REDCOLOR}ERROR! The file {absPath} is not in the source directory {sd}{RESETCOLOR}")
        exit(1)
    
    logEntry = get_git_log(sd, absPath)
    authors = get_all_file_authors(logEntry)

    lastModificationDate = get_last_modification_date(logEntry)
    header = make_header(authors, lastModificationDate, args.file, args.project)

    headerNumLines = header.count("\n")
    # check if the first lines of the file are the header
    with open(args.file, "r") as f:
        # Add the header to the file
        with open(args.file, "r") as f:
            fileContent = f.read()

        # remove any old version of the header
        fileContent = HEADER_PATTERN.sub("", fileContent)

        with open(args.file, "w") as f:
            f.write(header)
            f.write(fileContent)
