#!/usr/bin/env python

import os
import sys
import click
import colored
import logging

from sh import git
from enum import Enum
from pathlib import Path

from git import Repo

from prompt_toolkit import prompt
from prompt_toolkit.styles import Style
from prompt_toolkit.shortcuts import radiolist_dialog
from prompt_toolkit.shortcuts import yes_no_dialog

try:
    repo = Repo(".")
except:
    print("Not in a repo directory!")
    exit()


class RepoManager:
    @staticmethod
    def get_list_branches(ignore_current=True):
        return [
            branch.name
            for branch in repo.branches
            if branch.name != repo.active_branch.name
        ]

    @staticmethod
    def get_autocomplete_list_branches(ctx, args, incomplete):
        return [
            branch.name
            for branch in RepoManager.get_list_branches()
            if incomplete in branch.name
        ]

    @staticmethod
    def verify_branch():
        return yes_no_dialog(
            title="Branch Verification",
            text=f"Current Branch: {repo.active_branch.name} is this correct?",
        ).run()

    @staticmethod
    def cherry(first, second):
        cmd = ["cherry", "-v", first, second]
        response = git(cmd).strip().split("\n")

        commits = []

        for commit in response:
            commit = commit.split(" ")

            commits.append(" ".join(commit[2:]))

        return commits

    @staticmethod
    def recent_branches(count=os.environ.get("RECENT_COUNT", 5)):
        cmd = [
            "for-each-ref",
            f"--count={count}",
            "--sort=-committerdate",
            "refs/heads/",
            "--format=%(refname:short)",
        ]
        response = git(cmd)
        return response


class AuthorManager:
    def __init__(self):
        import json

        self.authors = None

        if os.path.exists("authors.json"):
            with open("authors.json", "r") as f:
                self.authors = json.loads(f.read())
                self.authors = self.authors["authors"]

    def ask(self):
        if self.authors:
            authors = []

            for index, author in enumerate(self.authors):
                name = f"{author['name']} <{author['email']}>"
                authors.append((name, name))

            response = radiolist_dialog(
                title="Reviewer Picker", text="Who reviewed this?", values=authors,
            ).run()

            if response != None:
                return response

        name = prompt("Whats the reviewers name?: ")
        email = prompt("Whats the reviewers email?: ")

        return f"{name} <{email}>"


class Printer:
    def _default_label_colors(self):
        return colored.fg("white")

    def _default_value_colors(self):
        return colored.fg("white")

    def _generate_label_colors(self, colors):
        if colors:
            return colors
        else:
            return self._default_label_colors()

    def _generate_value_colors(self, colors):
        if colors:
            return colors
        else:
            return self._default_value_colors()

    def autocomplete(self):
        path_folder = os.path.dirname(__file__)
        path = Path(path_folder)
        path_autocomplete = os.path.join(path)

        print(
            f"""{colored.fg("green")}AUTOCOMPLETE
===============
ZSH:
source {path_autocomplete}/merger-zsh-complete.sh

FISH:
source {path_autocomplete}/merger-fish-complete.sh

BASH:
source {path_autocomplete}/merger-bash-complete.sh
"""
        )

    def banner(self, message="Merger"):
        from pyfiglet import print_figlet

        print_figlet(message, colors="LIGHT_CYAN")

    def merged(
        self,
        label_colors=colored.fg("white") + colored.bg("green"),
        value_colors=colored.fg("white") + colored.bg("green"),
    ):
        label_colors = self._generate_label_colors(label_colors)
        value_colors = self._generate_value_colors(value_colors)

        print(f"{label_colors}Merger: {value_colors} Successfully merged!")

    def branches(
        self, label_colors=None, value_colors=None,
    ):
        print(
            f"""{colored.fg('yellow')}Current Branch:\n===============\n{repo.active_branch.name}\n"""
        )
        print(
            f"""{colored.fg('yellow')}Recent Branches ({os.environ.get("RECENT_COUNT", 5)})\n==============="""
        )
        print(str(RepoManager.recent_branches()) + colored.fg("white"))

    def recent_branches(
        self, label_colors=None, value_colors=None,
    ):
        label_colors = self._generate_label_colors(label_colors)
        value_colors = self._generate_value_colors(value_colors)

    def space(self):
        print("\n")

    def invalid_branch(
        self,
        branch,
        label_colors=colored.fg("white") + colored.bg("red"),
        value_colors=colored.fg("white") + colored.bg("red"),
    ):
        label_colors = self._generate_label_colors(label_colors)
        value_colors = self._generate_value_colors(value_colors)
        print(
            f"{label_colors}Error: {value_colors} {branch} is not correct! Please try again."
        )

    def error(
        self,
        label,
        error,
        label_colors=colored.fg("white") + colored.bg("red"),
        value_colors=colored.fg("white") + colored.bg("red"),
    ):
        label_colors = self._generate_label_colors(label_colors)
        value_colors = self._generate_value_colors(value_colors)
        print(f"{label_colors}{label}: {value_colors} { error }")


printer = Printer()


@click.group(invoke_without_command=True)
def cli():
    build = os.environ.get("BUILD", "0")

    if build == "0":
        printer.banner()
        printer.autocomplete()
        printer.branches()

    ctx = click.get_current_context()
    click.echo(ctx.get_help())
    ctx.exit()


@cli.command()
@click.argument(
    "branch",
    type=click.Choice(RepoManager.get_list_branches()),
    autocompletion=RepoManager.get_list_branches,
)
def merge(branch):
    """
    Merges and squashs a branch into the current branch.

    BRANCH Name of branch to merge
    
    """

    if RepoManager.verify_branch():
        authorManager = AuthorManager()

        author = authorManager.ask()

        if author is None:
            printer.error("Author", "Not chosen")
            exit()

        commits = "\n".join(RepoManager.cherry(repo.active_branch, branch))

        commit_message = f"""{commits}

Reviewed By: {author}"""

        repo.git.merge("--squash", "--no-log", branch)
        repo.index.commit(commit_message)

        printer.merged()

    else:
        printer.invalid_branch(repo.active_branch.name)


def main():
    cli()


if __name__ == "__main__":
    main()
