"""
Entry point for cov_change.
"""

import json
import os
from dataclasses import dataclass
from cov_change.coverage_parser import CoverageParser
from cov_change.diff_parser import DiffParser
import argparse
import subprocess
from rich.console import Console
from rich.table import Table


class bcolors:
    HEADER = "\033[95m"
    OKBLUE = "\033[94m"
    OKCYAN = "\033[96m"
    OKGREEN = "\033[92m"
    WARNING = "\033[93m"
    FAIL = "\033[91m"
    ENDC = "\033[0m"
    BOLD = "\033[1m"
    UNDERLINE = "\033[4m"


def build_table(json_data: dict, verbose: bool) -> Table:
    """
    Build a rich table from the json data.
    """
    table = Table()
    columns = ["File", "Coverage", "# Executed", "# Missed"]
    if verbose:
        columns += ["Missed Lines"]

    for column in columns:
        table.add_column(column)
    for file in json_data["files"].values():
        row = [
            file["file_name"],
            f"{file['coverage_percent']:.2f}%",
            str(len(file["executed_lines"])),
            str(len(file["missed_lines"])),
        ]
        if verbose:
            row.append(file["missed_lines_str"])

        table.add_row(*row)

    return table


@dataclass
class Args:
    diff_branch: str
    curr_branch: str
    coverage_file: str
    output: str
    verbose: bool
    diff_file: str
    use_coverage_change: bool


def _cov_change(args: Args) -> None:
    json_data = None

    if args.use_coverage_change:
        if os.path.exists(args.output):
            with open(args.output, "r") as f:
                json_data = json.load(f)
        else:
            print(f"{args.output} not found")
            exit(1)
    else:
        if args.diff_file is None:
            output = subprocess.run(
                ["git", "diff", "--unified=0", args.diff_branch, args.curr_branch],
                capture_output=True,
            )
            data = output.stdout.decode("utf-8")

        else:
            if not os.path.exists(args.diff_file):
                raise Exception(f"{args.diff_file} not found")
            with open(args.diff_file, "r") as f:
                data = f.read()
        diff_parser = DiffParser(data)
        diff_parser.parse()
        coverage_parser = CoverageParser(args.coverage_file, diff_parser)
        coverage_parser.parse()
        json_data = coverage_parser.json()
        with open(args.output, "w") as f:
            f.write(json_data)
        json_data = json.loads(json_data)
    print(
        f"{bcolors.OKCYAN}{bcolors.BOLD}Coverage of changes{bcolors.ENDC}: {bcolors.OKCYAN}{json_data['total_coverage']:.2f}%{bcolors.ENDC}"
    )
    table = build_table(json_data, args.verbose)
    console = Console()
    console.print(table, overflow="fold")


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "diff_branch",
        nargs="?",
        help="diff branch/commit to compare against (default: origin/main)",
        default="origin/main",
    )
    parser.add_argument(
        "curr_branch",
        nargs="?",
        help="current branch/commit to compare (default: HEAD)",
        default="HEAD",
    )
    parser.add_argument(
        "--coverage_file",
        help="coverage file generated by running 'coverage json'",
        default="coverage.json",
        required=False,
    )
    parser.add_argument(
        "-o",
        "--output",
        help="json output file",
        default="coverage_change.json",
        required=False,
    )
    parser.add_argument(
        "-v",
        "--verbose",
        help="print extra information",
        default=False,
        required=False,
        action="store_true",
    )

    parser.add_argument(
        "--diff-file",
        help="diff file already generated by running 'git diff --unified=0 <diff_branch> <curr_branch>'",
        default=None,
        required=False,
    )
    parser.add_argument(
        "--use_coverage_change",
        help="use coverage change file generated by previous run",
        default=False,
        action="store_true",
    )

    args: Args = Args(**vars(parser.parse_args()))
    _cov_change(args)


if __name__ == "__main__":
    main()
