# -*- coding: utf-8 -*-
""" Confluence sender module """

from typing import Optional

import plotly

from ..utils.csv_parser import CSVParser
from ..utils.logger_config import setup_logger, DEFAULT_LOGGING_LEVEL

# Set path to orca for plotly
plotly.io.orca.config.executable = "/usr/local/bin/orca"


class PlotlyReporter:
    """Class contains wrapper for generated reports (images) via plot charts"""

    def __init__(
        self,
        pr_colors=None,
        pr_labels=None,
        ar_colors=None,
        lines=None,
        type_platforms=None,
        logger=None,
        log_level=DEFAULT_LOGGING_LEVEL,
    ):
        """
        General init

        :param pr_colors: default colors for different priorities, list with rgb, (usually 1-4 values), optional
        :param pr_labels: default labels for different priorities, list with strings (usually 1-4 values), optional
        :param ar_colors: default colors for different sections (platforms), list  with rgb, optional
        :param lines: default settings for lines, dict like {'color': 'rgb(0,0,51)', 'width': 1.5}, optional
        :param type_platforms: list of dicts, with sections ids, where dict = {'name': 'UI',
                                                                               'sections': [16276]}, optional
        :param logger: logger object, optional
        :param log_level: logging level, optional, by default is 'logging.DEBUG'
        """
        if not logger:
            self.___logger = setup_logger(name="PlotlyReporter", log_file="PlotlyReporter.log", level=log_level)
        else:
            self.___logger = logger
        self.___logger.debug("Initializing Plotly Reporter")
        if not type_platforms:
            raise ValueError("Platform types is not provided, Plotly Reporter cannot be initialized!")
        self.__pr_labels = pr_labels if pr_labels else ["Low", "Medium", "High", "Critical"]
        self.__pr_colors = (
            pr_colors if pr_colors else ["rgb(173,216,230)", "rgb(34,139,34)", "rgb(255,255,51)", "rgb(255, 153, 153)"]
        )
        self.__ar_colors = (
            ar_colors
            if ar_colors
            else [
                "rgb(255, 153, 153)",
                "rgb(255,255,51)",
                "rgb(34,139,34)",
                "rgb(173,216,230)",
                "rgb(65,105,225)",
                "rgb(192, 192, 192)",
            ]
        )
        self.__lines = lines if lines else ({"color": "rgb(0,0,51)", "width": 1.5})
        self.__type_platforms = type_platforms

    def draw_automation_state_report(self, filename=None, reports=None, state_markers=None):
        """
        Generates an image file (png) with staked distribution (bar chart) with automation type coverage (or similar).

        :param filename: output filename for image, png expected, required
        :param reports: report with stacked distribution, usually it's output of
                        ATCoverageReporter().automation_state_report()
        :param state_markers: list of dicts, contains settings for markers on chart like the following:
                                {
                                "marker": {"color": "rgb(34,139,34)", "line": {"color": "rgb(0,0,51)", "width": 1.5}},
                                "opacity": 0.6,
                                "textposition": "auto",
                                }
        :return: none
        """
        if not reports:
            raise ValueError("No TestRail reports are provided, report aborted!")
        if not filename:
            raise ValueError("No output filename is provided, report aborted!")
        data = []
        axis_x = []
        axis_y_automated = []
        axis_y_not_automated = []
        axis_y_na = []

        for report in reports:
            axis_x.append(report.get_name())
            axis_y_automated.append(report.get_automated())
            axis_y_not_automated.append(report.get_not_automated())
            axis_y_na.append(report.get_not_applicable())

        if not state_markers:
            state_markers = {
                "Automated": {
                    "marker": {"color": "rgb(34,139,34)", "line": {"color": "rgb(0,0,51)", "width": 1.5}},
                    "opacity": 0.6,
                    "textposition": "auto",
                },
                "Not automated": {
                    "marker": {"color": "rgb(255, 153, 153)", "line": {"color": "rgb(0,0,51)", "width": 1.5}},
                    "opacity": 0.6,
                    "textposition": "auto",
                },
                "N/A": {
                    "marker": {"color": "rgb(192, 192, 192)", "line": {"color": "rgb(0,0,51)", "width": 1.5}},
                    "opacity": 0.6,
                    "textposition": "auto",
                },
            }

        data.append(
            plotly.graph_objs.Bar(
                x=axis_x,
                y=axis_y_automated,
                text=axis_y_automated,
                name="Automated",
                textposition=state_markers["Automated"]["textposition"],
                marker=state_markers["Automated"]["marker"],
                opacity=state_markers["Automated"]["opacity"],
            )
        )
        data.append(
            plotly.graph_objs.Bar(
                x=axis_x,
                y=axis_y_not_automated,
                text=axis_y_not_automated,
                name="Not automated",
                textposition=state_markers["Not automated"]["textposition"],
                marker=state_markers["Not automated"]["marker"],
                opacity=state_markers["Not automated"]["opacity"],
            )
        )
        data.append(
            plotly.graph_objs.Bar(
                x=axis_x,
                y=axis_y_na,
                text=axis_y_na,
                name="N/A",
                textposition=state_markers["N/A"]["textposition"],
                marker=state_markers["N/A"]["marker"],
                opacity=state_markers["N/A"]["opacity"],
            )
        )

        layout = plotly.graph_objs.Layout(barmode="stack")
        self.___logger.debug("Drawing chart to file %s", filename)
        fig = plotly.graph_objs.Figure(data=data, layout=layout)
        plotly.io.write_image(fig, filename)

    def draw_test_case_by_priority(self, filename=None, values=None, pr_labels=None, pr_colors=None, lines=None):
        """
        Generates an image file (png) with priority distribution (pie chart)

        :param filename: output filename for image, png expected, required
        :param values: list of values to draw report with priority distribution, usually it's output from
                       ATCoverageReporter().test_case_by_priority()
        :param pr_labels: default labels for different priorities, list with strings (usually 1-4 values), optional
        :param pr_colors: default colors for different priorities, list with rgb, (usually 1-4 values), optional
        :param lines: default settings for lines, dict like {'color': 'rgb(0,0,51)', 'width': 1.5}, optional
        :return: none
        """
        if not values:
            raise ValueError("No TestRail values are provided, report aborted!")
        if not filename:
            raise ValueError("No output filename is provided, report aborted!")
        pr_labels = pr_labels if pr_labels else self.__pr_labels
        pr_colors = pr_colors if pr_colors else self.__pr_colors
        lines = lines if lines else self.__lines
        fig = {
            "data": [
                {
                    "values": values,
                    "labels": pr_labels,
                    "domain": {"column": 0},
                    "name": "Test cases by priority",
                    "hoverinfo": "label+percent+name",
                    "textinfo": "value+percent",
                    "type": "pie",
                    "marker": {"colors": pr_colors, "line": lines},
                },
            ]
        }
        self.___logger.debug("Drawing chart to file %s", filename)
        plotly.io.write_image(fig, filename)

    def draw_test_case_by_area(self, filename=None, cases=None, ar_colors=None, lines=None):
        """
        Generates an image file (png) with sections distribution (pie chart)

        :param filename: output filename for image, png expected, required
        :param cases: list of values to draw report with priority distribution, usually it's output from
                       ATCoverageReporter().test_case_by_type()
        :param ar_colors: default colors for different sections (platforms), list  with rgb, optional
        :param lines: default settings for lines, dict like {'color': 'rgb(0,0,51)', 'width': 1.5}, optional
        :return: none
        """
        if not cases:
            raise ValueError("No TestRail cases are provided, report aborted!")
        if not filename:
            raise ValueError("No output filename is provided, report aborted!")
        # priority distribution
        ar_colors = ar_colors if ar_colors else self.__ar_colors
        lines = lines if lines else self.__lines
        # area distribution
        ar_labels = []
        ar_values = []
        for case in cases:
            ar_labels.append(case.get_name())
            ar_values.append(case.get_total())

        fig = {
            "data": [
                {
                    "values": ar_values,
                    "labels": ar_labels,
                    "domain": {"column": 0},
                    "name": "Test cases by area",
                    "hoverinfo": "label+percent+name",
                    "textinfo": "value+percent",
                    "type": "pie",
                    "marker": {"colors": ar_colors, "line": lines},
                },
            ]
        }

        self.___logger.debug("Drawing chart to file %s", filename)
        plotly.io.write_image(fig, filename)

    def draw_history_state_chart(
        self,
        chart_name: Optional[str] = None,
        history_data=None,
        filename=None,
        trace1_decor=None,
        trace2_decor=None,
        filename_pattern="current_automation",
        reverse_traces=False,
    ):
        """
        Generates image file (png) with state distribution (staked line chart)

        :param chart_name: chart name, string, required
        :param history_data: history data, previously stored in CSV, by default it is CSVParser().load_history_data()
        :param filename: output filename for image, png expected, optional
        :param trace1_decor: decoration for distribution stack (1), dict like {"fill": "tonexty",
                                                                               "line": {"width": 0.5,
                                                                                        "color": "rgb(255, 153, 153)"},
                                                                               "mode": "none"}
        :param trace2_decor: decoration for distribution stack (2), dict like {"fill": "tozeroy",
                                                                               "line": {"width": 0.5,
                                                                                        "color": "rgb(34,139,34)"},
                                                                                "mode": "none"}
        :param filename_pattern: pattern, what is prefix will be for filename, string, optional
        :param reverse_traces: reverse traces order
        :return: none
        """
        if chart_name is None:
            raise ValueError("No chart name is provided, report aborted!")
        filename = filename if filename else f"{filename_pattern}_{chart_name.replace(' ', '_')}.csv"
        trace1_decor = (
            trace1_decor
            if trace1_decor
            else {"fill": "tonexty", "line": {"width": 0.5, "color": "rgb(255, 153, 153)"}, "mode": "none"}
        )
        trace2_decor = (
            trace2_decor
            if trace2_decor
            else {"fill": "tozeroy", "line": {"width": 0.5, "color": "rgb(34,139,34)"}, "mode": "none"}
        )

        history_data = (
            history_data
            if history_data
            else CSVParser(log_level=self.___logger.level, filename=filename).load_history_data()
        )
        trace1 = plotly.graph_objs.Scatter(
            x=history_data[0],
            y=history_data[1],
            fill=trace1_decor["fill"],
            name="Total",
            line=trace1_decor["line"],
        )
        trace2 = plotly.graph_objs.Scatter(
            x=history_data[0],
            y=history_data[2],
            fill=trace2_decor["fill"],
            name="Automated",
            line=trace2_decor["line"],
        )

        fig = plotly.graph_objs.Figure()
        if reverse_traces:
            fig.add_trace(trace2)
            fig.add_trace(trace1)
        else:
            fig.add_trace(trace1)
            fig.add_trace(trace2)
        fig.update_layout(yaxis={"nticks": 30}, autotypenumbers="convert types")
        fig.update_yaxes(range=[0, max((eval(i) for i in history_data[1]))])  # pylint: disable=eval-used

        filename = f"{filename[:-3]}png"
        self.___logger.debug("Drawing chart to file %s", filename)
        plotly.io.write_image(fig, filename)
        return filename

    def draw_history_type_chart(
        self,
        filename=None,
        type_platforms=None,
        history_filename_pattern="current_area_distribution",
        ar_colors=None,
        lines=None,
    ):
        """
        Generates an image file (png) with state distribution (staked line chart)

        :param filename: output filename for image, png expected, required
        :param type_platforms: list of dicts, with sections ids, where dict = {'name': 'UI',
                                                                               'sections': [16276]}, optional
        :param history_filename_pattern: pattern, what is prefix will be for filename, string, optional
        :param ar_colors: default colors for different sections (platforms), list  with rgb, optional
        :param lines: default settings for lines, dict like {'color': 'rgb(0,0,51)', 'width': 1.5}, optional
        :return: none
        """
        if not filename:
            raise ValueError("No output filename is provided, report aborted!")
        type_platforms = type_platforms if type_platforms else self.__type_platforms
        ar_colors = ar_colors if ar_colors else self.__ar_colors
        data = []
        lines = lines if lines else self.__lines
        index = 0
        for platform in type_platforms:
            type_name = platform["name"]
            history_filename = f"{history_filename_pattern}_{type_name.replace(' ', '_')}.csv"
            history_data = CSVParser(log_level=self.___logger.level, filename=history_filename).load_history_data()
            data.append(
                plotly.graph_objs.Scatter(
                    x=history_data[0],
                    y=history_data[1],
                    name=type_name,
                    marker={"color": ar_colors[index], "line": lines},
                )
            )
            index += 1
        fig = {"data": data}
        self.___logger.debug("Drawing chart to file %s", filename)
        plotly.io.write_image(fig, filename)
