# -*- coding: utf-8 -*-
import json
import logging

from tabulate import tabulate

import lib.aggregate as aggregate
import lib.config as config

LOG = logging.getLogger(__name__)


def find_tool_shortname(desc):
    """Find the short name for the tool given its description.
    SARIF file contains the description for the tool

    :param desc Description of the tool
    :param return short name
    """
    for key, value in config.tool_purpose_message.items():
        if value.lower() == desc.lower():
            return key
    return desc


def summary(sarif_files, aggregate_file=None, override_rules={}):
    """Generate overall scan summary based on the generated
    SARIF file

    :param sarif_files: List of generated sarif report files
    :param aggregate_file: Filename to store aggregate data
    :param override_rules Build break rules to override for testing
    :returns dict representing the summary
    """
    report_summary = {}
    build_status = "pass"
    # This is the list of all runs which will get stored as an aggregate
    run_data_list = []
    for sf in sarif_files:
        with open(sf, mode="r") as report_file:
            report_data = json.loads(report_file.read())
            # skip this file if the data is empty
            if not report_data or not report_data.get("runs"):
                LOG.warn("Report file {} is invalid. Skipping ...".format(sf))
                continue
            # Iterate through all the runs
            for run in report_data["runs"]:
                # Add it to the run data list for aggregation
                run_data_list.append(run)
                tool_desc = run["tool"]["driver"]["name"]
                tool_name = find_tool_shortname(tool_desc)
                # Initialise
                report_summary[tool_name] = {
                    "tool": tool_name,
                    "description": tool_desc,
                    "critical": 0,
                    "high": 0,
                    "medium": 0,
                    "low": 0,
                    "status": "✅",
                }
                results = run.get("results", [])
                metrics = run.get("properties", {}).get("metrics", None)
                # If the result includes metrics use it. If not compute it
                if metrics:
                    report_summary[tool_name].update(metrics)
                    report_summary[tool_name].pop("total", None)
                else:
                    for aresult in results:
                        sev = aresult["properties"]["issue_severity"].lower()
                        report_summary[tool_name][sev] += 1
                # Compare against the build break rule to determine status
                default_rules = config.get("build_break_rules").get("default")
                tool_rules = config.get("build_break_rules").get(tool_name, {})
                build_break_rules = {**default_rules, **tool_rules, **override_rules}
                for rsev in ["critical", "high", "medium", "low"]:
                    if build_break_rules.get("max_" + rsev) is not None:
                        if (
                            report_summary.get(tool_name).get(rsev)
                            > build_break_rules["max_" + rsev]
                        ):
                            report_summary[tool_name]["status"] = "❌"
                            build_status = "fail"
    # Should we store the aggregate data
    if aggregate_file:
        aggregate.jsonl_aggregate(run_data_list, aggregate_file)
        LOG.debug("Aggregate report written to {}\n".format(aggregate_file))
    return report_summary, build_status


def print_summary(report_summary):
    """Pretty print report summary
    """
    table = []
    headers = None
    for k, v in report_summary.items():
        if not headers:
            headers = v.keys()
        table.append(v.values())
    print("\n")
    print(tabulate(table, headers, tablefmt="simple"))
