#!/usr/bin/env python
# -*- coding: utf-8 -*-
import argparse
import logging
import os
import sys
import re
from subprocess import Popen, PIPE
from tabulate import tabulate
from time import strftime

logger = logging.getLogger("NaoStatus")
logger.setLevel(logging.INFO)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
formatter = logging.Formatter('[%(levelname)s]%(name)s: %(message)s')
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)

nao_path = os.path.dirname(os.path.realpath(__file__)) + "/.."
wiki_path = nao_path + "/.wiki"
nao_numbers = set()


def check_wiki():
    """
    Checks if there is a local copy of the wiki,
    if not clones it. If there is one it performs a git pull
    """
    if os.path.isdir(wiki_path):
        logger.info("Local wiki found.")
    else:
        logger.info("Couldn't find local wiki, cloning...")
        os.chdir(nao_path)
        os.system("git clone --depth 1 git@github.com:hulks/nao.wiki.git .wiki")

    # create the current team
    global nao_numbers
    for file_path in os.listdir(wiki_path):
        if "tuhhnao" in file_path:
            nao_numbers.add(re.findall("tuhhnao(\d\d)_(?:head|body).md", file_path)[0])
    nao_numbers = sorted(list(nao_numbers))


def get_head_or_body(nao_number, head_or_body):
    """
    Reads a NaoStatus wiki entry and returns
    head, body or both parts
    """
    if head_or_body == "both":
        with open(wiki_path + "/tuhhnao{}_head.md".format(nao_number), 'r') as file:
            head_content = file.read()
            head_matches = re.findall(r"(?:\|\s*)([\w\s.\-\(\)\#\'\[\]\,\;\:]*?)(?:\s*\|\s*)(\d{4}-\d{2}-\d{2})(?:\s*\|)", head_content)
            if len(head_matches) == 0:
                head_matches = [("Empty status", "Empty date")]
        with open(wiki_path + "/tuhhnao{}_body.md".format(nao_number), 'r') as file:
            body_content = file.read()
            body_matches = re.findall(r"(?:\|\s*)([\w\s.\-\(\)\#\'\[\]\,\;\:]*?)(?:\s*\|\s*)(\d{4}-\d{2}-\d{2})(?:\s*\|)", body_content)
            if len(body_matches) == 0:
                body_matches = [("Empty status", "Empty date")]

        head_preheader = "\n".join(head_content.splitlines()[:2]) + "\n"
        body_preheader = "\n".join(body_content.splitlines()[:2]) + "\n"

        return head_preheader, head_matches, body_preheader, body_matches

    else:
        with open(wiki_path + "/tuhhnao{}_{}.md".format(nao_number, head_or_body), 'r') as file:
            content = file.read()
            matches = re.findall(r"(?:\|\s*)([\w\s.\-\(\)\#\'\[\]\,\;\:]*?)(?:\s*\|\s*)(\d{4}-\d{2}-\d{2})(?:\s*\|)", content)
            if len(matches) == 0:
                matches = [("Empty status", "Empty date")]

        preheader = "\n".join(content.splitlines()[:2]) + "\n"

        return preheader, matches


def main_add(args):
    """
    Adds a line to the wiki entry for the tuhhnao{nao_number}
    """
    if not args.no_sync:
        rebase(args)

    if args.message is None:
        logger.error("The add command needs a message. Specify it with -m")
        sys.exit(1)

    # case asking for head and body
    if args.head_or_body == "both":
        # add the message to both head and body
        head_preheader, head_lines, body_preheader, body_lines = get_head_or_body(args.nao_number, args.head_or_body)
        head_lines.append((args.message, args.date))
        body_lines.append((args.message, args.date))

        # pretty format the table
        head_content = head_preheader + tabulate(head_lines, ["Status", "Date"], tablefmt="pipe")
        body_content = body_preheader + tabulate(body_lines, ["Status", "Date"], tablefmt="pipe")

        #  write to files
        with open(wiki_path + "/tuhhnao{}_head.md".format(args.nao_number), 'w') as file:
            file.write(head_content)
        with open(wiki_path + "/tuhhnao{}_body.md".format(args.nao_number), 'w') as file:
            file.write(body_content)

        logger.info("Saved message: \"{}\" for nao {} head and body.".format(args.message, args.nao_number))

    else:
        # add the message
        preheader, lines = get_head_or_body(args.nao_number, args.head_or_body)
        lines.append((args.message, args.date))

        # pretty format the table
        content = preheader + tabulate(lines, ["Status", "Date"], tablefmt="pipe")

        # write to file
        with open(wiki_path + "/tuhhnao{}_{}.md".format(args.nao_number, args.head_or_body), 'w') as file:
            file.write(content)

        logger.info("Saved message: \"{}\" for nao {} {}.".format( args.message, args.nao_number, args.head_or_body))

    # commit and sync
    commit("add", args)

    if not args.no_sync:
        push(args)


def main_modify(args):
    """
    Modifies last message in wiki with new message
    """

    if not args.no_sync:
        rebase(args)

    if args.message is None:
        logger.error("The modify command needs a message. Specify it with -m.")
        sys.exit(1)

	# change the last line
    preheader, lines = get_head_or_body(args.nao_number, args.head_or_body)
    last_line = lines[-1]
    lines[-1] = (args.message, args.date)

    # pretty format the table
    content = preheader + tabulate(lines, ["Status", "Date"], tablefmt="pipe")

	# write to file
    with open(wiki_path + "/tuhhnao{}_{}.md".format(args.nao_number, args.head_or_body), 'w') as file:
        file.write(content)

    logger.info("Modified last status message to: \"{}\" for nao {} {}.".format(args.message, args.nao_number, args.head_or_body))

    # commit and sync
    commit("modify", args)

    if not args.no_sync:
        push(args)


def main_status(args):
    """
    Prints what is currently saved in tuhhnao{nao_number}'s status entry
    """
    if args.nao_number == "team":
        team_message_lines = []
        for nao_number in nao_numbers:
            team_message_lines.append("+++++++++++ Nao {} +++++++++++".format(nao_number))
            head_preheader, head_lines, body_preheader, body_lines = get_head_or_body(nao_number, args.head_or_body)
            team_message_lines.append("Head - {}, {}".format(head_lines[-1][0], head_lines[-1][1]))
            team_message_lines.append("Body - {}, {}".format(body_lines[-1][0], body_lines[-1][1]))
            team_message_lines.append("")
        print("\n".join(team_message_lines))

    else:
        if args.head_or_body == "both":
            with open(wiki_path + "/tuhhnao{}_head.md".format(args.nao_number), 'r') as file:
                print(file.read())
                print("")
            with open(wiki_path + "/tuhhnao{}_body.md".format(args.nao_number), 'r') as file:
                print(file.read())
        else:
            with open(wiki_path + "/tuhhnao{}_{}.md".format(args.nao_number, args.head_or_body), 'r') as file:
                print(file.read())


def rebase(args):
    """
    Rebases onto the master
    """
    os.chdir(wiki_path)
    os.system("git pull origin master --rebase")


def commit(command, args):
    """
    Commits the current changes
    """
    os.chdir(wiki_path)
    os.system("git commit -am \"naoStatus.py {} nao:{}, message:{}, part:{}\"".format(command, args.nao_number, args.message, args.head_or_body))


def push(args):
    """
    Pushes to master
    """
    os.chdir(wiki_path)
    os.system("git push origin master")


def sync_main(args):
    """
    Syncs the wiki repository
    """
    rebase(args)
    push(args)


def main():
    arg_parser = argparse.ArgumentParser(description="Nao status management tool for the hulks github wiki",
                                         formatter_class=argparse.RawTextHelpFormatter)
    subparsers = arg_parser.add_subparsers()

    # parser arguments for add command
    parser_add = subparsers.add_parser('add', help='Add command appends a line to the nao\'s status entry in the wiki')
    parser_add.add_argument('nao_number', type=str, help='Number of the target nao')
    parser_add.add_argument("head_or_body", default="both", choices=["head", "body", "both"], type=str)
    parser_add.add_argument('-m', "--message", default=None, type=str, help="The message passed to our wiki")
    parser_add.add_argument('-d', "--date", default=strftime("%Y-%m-%d"), type=str, help="The date passed to our wiki, default is today")
    parser_add.add_argument('-n', '--no-sync', action='store_true', default=False, help="Keeps the script from syncing with the wiki")
    parser_add.set_defaults(func=main_add)

    # parser arguments for modify command
    parser_modify = subparsers.add_parser('modify', help='Modify the last line of the nao\'s status entry in the wiki')
    parser_modify.add_argument('nao_number', type=str, help='Number of the target nao')
    parser_modify.add_argument("head_or_body", default="both", choices=["head", "body", "both"], type=str)
    parser_modify.add_argument('-m', "--message", default=None, type=str, help="The message passed to our wiki")
    parser_modify.add_argument('-d', "--date", default=strftime("%Y-%m-%d"), type=str, help="The date passed to our wiki, default is today")
    parser_modify.add_argument('-n', '--no-sync', action='store_true', default=False, help="Keeps the script from syncing with the wiki")
    parser_modify.set_defaults(func=main_modify)

    # parser arguments for status command
    parser_status = subparsers.add_parser('show', help='Print the nao\'s status entry in the wiki')
    parser_status.add_argument('nao_number', default="team", nargs='?', type=str, help='Number of the target nao')
    parser_status.add_argument("head_or_body", default="both", nargs="?", choices=["head", "body", "both"], type=str)
    parser_status.set_defaults(func=main_status)

    # parser arguments for the sync command
    parser_sync = subparsers.add_parser('sync', help='Sync the wiki with github')
    parser_sync.set_defaults(func=sync_main)

    # parse all arguments
    args = arg_parser.parse_args()

    # check for iso date format
    if hasattr(args, "date"):
        if not re.match('([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))', args.date):
            logger.error("Date needs to be iso formatted! E.g.: 2018-09-29")
            sys.exit(1)

    # check the nao number
    if hasattr(args, "nao_number"):
        if not args.nao_number.isdigit() and not args.nao_number == "team":
            logger.error("Use \"team\" or a specific nao number, not: {}".format(args.nao_number))
            sys.exit(1)

    # check the wiki
    check_wiki()

    # call respective main
    if len(sys.argv) > 1:
        args.func(args)
    else:
        arg_parser.print_help()

if __name__ == '__main__':
    # parse all given arguments, this function also decides which main to call
    main()
