from pathlib import Path
import report
import base64 as b64
from plotly.graph_objs import Figure


class CSS:
    def __init__(self, path=Path(report.__file__).parent / "style.css"):
        self.path = Path(path)

    def __str__(self):
        with open(self.path) as css_file:
            css_code = css_file.read()
        return css_code

    def __repr__(self):
        return "CSS"


class Content:
    def __init__(self):
        pass

    def render_html_str(self):
        pass


class Text(Content):
    def __init__(self, text, style=""):
        super().__init__()
        self.text = text
        self.style = style

    def render_html_str(self):
        html = f"""
                <div class="row offset-2">\n
                    <div class="col-9 mt-3 mb-0 pb-0">\n
                        <p style="{self.style}"class="text-justify">\n
                            {self.text} \n
                        </p>\n
                    </div>\n
                </div>\n
               """
        return html


class Img(Content):
    """
    """

    def __init__(self, path_to_img):
        self.path_to_img = Path(path_to_img)

    def render_html_str(self):
        html = ""
        return html

    def __repr__(self):
        return f"{self.path_to_img}"


class Title(Content):
    """
    """

    def __init__(self, title):
        self.title = title
        self.id = title

    def render_html_str(self):
        html = f"""
        <div class="row offset-2">
            <div class="col-9">
                <h1 class="h1"><a id="{self.id}"></a>
                    {self.title}
                </h1>
            </div>
        </div>
"""

        return html


class Page:
    """
    """

    def __init__(
            self, content=None,
    ):

        for item in content:
            assert isinstance(item, Content) or isinstance(
                item, str
            ), "Every item of content must be either content or a string"
        self.content = content
        self._titles = []
        self._figures = []
        content = []
        for item in self.content:
            if isinstance(item, str):
                content.append(Text(item))
            else:
                content.append(item)
            if isinstance(item, Title):
                self._titles.append(item)
            if isinstance(item, PlotlyFigure) or isinstance(item, Img):
                self._figures.append(item)

    def render_html_str(self, figures_list):
        html = ""
        for item in self.content:
            if isinstance(item, PlotlyFigure):
                figure_numb = len(figures_list)
                item = PlotlyFigure(
                    item.figure, item.width, id="Figure " + f"{figure_numb}"
                )
                figures_list.append(item)
            html += item.render_html_str()

        return html, figures_list


class PlotlyFigure(Content):
    def __init__(self, figure, width=900, id=""):
        self.figure = figure
        self.figure.update_layout(width=width)
        self.id = id
        self.width = width

    def render_html_str(self):
        html = f"""
        <div style="width: {self.figure.layout["width"]}px;height: {self.figure.layout["height"]}px" class="mx-auto" id="{self.id}">\n
            {self.figure.to_html(full_html=False)}
        </div>
        """

        return html


class Table(Content):
    def __init__(self, pandas_data_frame, width):
        self.table = pandas_data_frame
        self.width = width

    def render_html_str(self):
        html = f"""
        <div style="width: {self.width}px;" class="mx-auto">\n
            {self.table.to_html(classes="table table-striped table-hover table-responsive")}
        </div>
        """
        return html


class Listing(Content):
    def __init__(self, items):
        self.items = items

    def __str__(self):
        return str(self.render_html_str())

    def render_html_str(self):
        html = """
        <div class="offset-2 mb-4 row">
                <div class="col-9">
                    <ui>
        """

        for item in self.items:
            html += f"""             <li style = "color: #555555; text-align: -webkit-match-parent;">{item}</li>\n"""

        html += """
                </ui>
            </div>
        </div>
        """
        return html


class Link(Content):
    def __init__(self, title, href, style="", internal=True):
        self.href = href
        self.title = title
        self.internal = internal
        self.style = style

    def render_html_str(self):
        return f"""<a style="{self.style}" class="text-justify" href = "{self._internal()}{self.href}">{self.title}</a>"""

    def _internal(self):
        if self.internal:
            return "#"
        else:
            return ""

    def __str__(self):
        return self.render_html_str()

    def __repr__(self):
        return self.render_html_str()


class Layout:
    """Report Layout
    """

    def __init__(
            self,
            summary=True,
            figures_list_ref=True,
            css=CSS(),
            pages=None,
            main_title="ROSS Report",
    ):
        assert (
                isinstance(pages, list) or isinstance(pages, Page) or pages is None
        ), "pages argument must be either a Page or a list of Pages."
        if isinstance(pages, list):
            for page in pages:
                assert isinstance(page, Page), "All items in page must be Pages."
            self.pages = pages
        else:
            self.pages = [pages]

        assert isinstance(css, CSS), "css must be an CSS object."
        self.css = css

        assert isinstance(main_title, str), "main_title must be a str."
        self.main_title = main_title

        self.summary = summary
        self.figures_list = []
        self.figures_list_ref = figures_list_ref

    def __repr__(self):
        rep = {}
        if isinstance(self.pages, list):
            for page in range(len(self.pages)):
                rep[self.pages[page]] = self.pages[page]
        elif isinstance(self.pages, Page):
            rep[self.pages] = self.pages.content
        return str(rep)

    def summary_renderer(self):
        layout_titles = []
        for page in self.pages:
            for title in page._titles:
                layout_titles.append(Link(title=title.title, href=title.title))
        if self.figures_list_ref:
            layout_titles.append(Link(title="Figures List", href="Figures List"))

        summary = f"""
            <div class="mt-4 pb-4 offset-2 row">
                <div class="col-9">
                    <h1 class="h1">
                        Summary 
                    </h1>
                </div>
            </div>
        """
        summary += str(Listing(layout_titles))
        return summary

    def figures_list_renderer(self):
        content = [Title("Figures List")]
        image_titles = []
        for figure in range(len(self.figures_list)):
            image_titles.append(
                Link(title=f"Figure {figure + 1}", href=f"Figure {figure}")
            )
        content.append(Listing(image_titles))
        print(len(self.figures_list))

        return content

    def render_pages(self, figures_list_ref=True):
        html = ""

        if self.summary is True:

            if isinstance(self.pages, list):
                figures_list = []
                for page in range(len(self.pages)):
                    rendered_page = self.pages[page].render_html_str(
                        figures_list=figures_list
                    )
                    html += rendered_page[0]
                    figures_list = rendered_page[1]

                    if page != len(self.pages) - 1:
                        html += """<<p class="page-break-before" style="page-break-before: always" /> \n>"""

                    elif figures_list_ref:
                        self.figures_list = figures_list
                        rendered_page = Page(
                            content=self.figures_list_renderer()
                        ).render_html_str(figures_list=figures_list)
                        html += rendered_page[0]
                        print(len(figures_list))

            elif isinstance(self.pages, Page):
                html += self.pages.render_html_str()

        return html

    def render_html_str(self):
        rendered_pages = self.render_pages(figures_list_ref=self.figures_list_ref)
        summary = self.summary_renderer()
        html = (
                """
            <!DOCTYPE html>
            <html lang="en">
            <head>
            <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
                """
                + """
            <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
            <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
            <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
            <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
            <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
            <script type="text/javascript" id="MathJax-script" async
              src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js">
            </script>
            """
        )
        html = (
                html
                + "<style>"
                + str(self.css)
                + "</style>"
                + """
            <style>
            
                @media print { 
                    @page {
                        size: A4; /* DIN A4 standard, Europe */
                        margin: 1cm;
                        }
                    .offset-2{
                        margin-left: 3cm;
                        margin-right: 0;
                        margin-top: .5cm;
                    }
                    .mt-img{
                        margin-top: 5cm;
                    }
                    p{
                        width: 100ch;
                    }
                    a,li{
                        margin-top: 0;
                        margin-bottom: 1rem;
                        color: #555555;
                    }
                }
            </style>
            <meta charset="UTF-8">
            <title>ROSS Report</title>
            <link rel="icon" href="data:image/svg+xml;base64, ">
        </head>
        <body>
    """
                + f"""
        <div class="container-fluid">
            
            <div class="mt-4 offset-2 row">
                <div class="col-9">
                    <h1 style= "font-size: 2.5rem" class="h1">
                        {self.main_title}
                    </h1>
                </div>

            <div class="col-3">
                <a href="https://github.com/ross-rotordynamics/ross-report">
                    <img id="ross-logo" src="data:image/svg+xml;base64, "/>
                </a>
            </div>
    
        </div>
        """
        )

        html += summary
        html += rendered_pages
        html += """
        
        </div>
        </body>
        </html>
        """
        return html
