# Copyright 2020 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This file contains a markdown story exporter."""

import datetime
import markdown


from timesketch.lib.stories import interface
from timesketch.lib.stories import manager


class HTMLStoryExporter(interface.StoryExporter):
    """HTML story exporter."""

    # String representing the output format of the story.
    EXPORT_FORMAT = "html"

    # Number of rows of a DataFrame to include at the top of a markdown table.
    _DATAFRAME_HEADER_ROWS = 30

    HTML_HEADER = (
        "<html>"
        "    <head>"
        '<script src="https://cdn.jsdelivr.net/npm/vega@5"></script>'
        '<script src="https://cdn.jsdelivr.net/npm/vega-lite@4"></script>'
        ' <script src="https://cdn.jsdelivr.net/npm/vega-embed@6"></script>'
        " </head>"
        " <body>"
    )

    HTML_FOOTER = "</body></html>"

    def _data_frame_to_html(self, data_frame):
        """Returns a HTML formatted string from a pandas DataFrame."""
        nr_rows, _ = data_frame.shape
        if not nr_rows:
            return "<b>empty table</b>"

        if nr_rows <= self._DATAFRAME_HEADER_ROWS:
            return data_frame.to_html(index=False)

        html_code = data_frame.to_html(
            index=False, max_rows=self._DATAFRAME_HEADER_ROWS
        )
        return (
            "{:s}\n<b>...</b><br/>"
            "<i>Table contains more records than are displayed. "
            "Only the first {:d} records out of total {:d} are "
            "printed out. View the full view in Timesketch to get all "
            "the results.</i>"
        ).format(html_code, self._DATAFRAME_HEADER_ROWS, nr_rows)

    def export_story(self):
        """Export the story as HTML."""
        return_strings = [self.HTML_HEADER]

        return_strings.append(f"<h1>{self._story_title:s}</h1>")
        date_now = datetime.datetime.utcnow()
        return_strings.append(
            "Story Metadata:<br/><ul><li><b>Creation Date:</b> {:s}</li>"
            "<li><b>Created by:</b> {:s}</li>"
            "<li><b>Report Generated:</b> {:s}</li>"
            "<li><b>Report Exported by:</b> {:s}</li></ul>".format(
                self._creation_date,
                self._story_author,
                date_now.isoformat(),
                self._story_exporter,
            )
        )

        md = markdown.Markdown()

        chart_number = 1
        charts = []
        for line_dict in self._data_lines:
            line_type = line_dict.get("type", "")
            if line_type == "text":
                return_strings.append(md.convert(line_dict.get("value", "")))

            elif line_type == "aggregation":
                data_dict = line_dict.get("value")
                agg_obj = data_dict.get("aggregation")
                chart_type = data_dict.get("chart_type")
                if chart_type == "table":
                    df = agg_obj.to_pandas()
                    return_strings.append(self._data_frame_to_html(df))
                else:
                    parameters = data_dict.get("parameters", {})
                    title = parameters.get("title", data_dict.get("name"))
                    chart_color = parameters.get("chart_color")

                    chart = agg_obj.to_chart(
                        chart_name=chart_type,
                        chart_title=title,
                        interactive=True,
                        color=chart_color,
                        as_chart=True,
                    )

                    charts.append(chart)
                    return_strings.append(f'<div id="vis{chart_number:d}"></div>')
                    chart_number += 1

            elif line_type == "dataframe":
                return_strings.append(self._data_frame_to_html(line_dict.get("value")))

            elif line_type == "chart":
                data_dict = line_dict.get("value")
                chart = data_dict.get("chart")

                charts.append(chart)
                return_strings.append(f'<div id="vis{chart_number:d}"></div>')
                chart_number += 1

        if charts:
            return_strings.append('<script type="text/javascript">')
            for index, chart in enumerate(charts):
                vis_nr = index + 1
                return_strings.append(
                    "vegaEmbed('#vis{:d}', {:s})."
                    "catch(console.error);".format(vis_nr, chart.to_json(indent=None))
                )
            return_strings.append("</script>")

        return_strings.append("</body></html>")
        return "\n\n".join(return_strings)


manager.StoryExportManager.register_exporter(HTMLStoryExporter)
