from pathlib import Path
from jinja2 import FileSystemLoader, TemplateNotFound, Environment

from xhtml2pdf import pisa
from datetime import date, timedelta

import markdown


class HtmlTemplate:
    def __init__(self, templates):
        self.template_name = 'invoice.html'
        if not Path(templates).exists():
            raise FileNotFoundError(f'Inivalid path to template files: {templates}')
        self.templates = templates
        self.path_to_template = Path(templates)

    def prepare_template(self, invoice_data, envelope_data):
        try:
            loader = FileSystemLoader(self.templates)
            env = Environment(loader=loader)
            env.globals['format_float'] = self.format_float
            env.globals['calculate_total'] = self.calculate_total

            env.filters['markdown_to_html'] = self.markdown_to_html
            env.filters['named_replace'] = self.named_replace
            env.filters['add_days'] = self.add_days

            template = env.get_template(self.template_name)
            return template.render(invoice=invoice_data, envelope=envelope_data)
        except TemplateNotFound:
            raise FileNotFoundError(f'Could not find template file: {self.template_name}')

    @staticmethod
    def calculate_total(invoice_data):
        return sum((pos['Quantity'] * pos['PricePerUnit']) for pos in invoice_data.Positions)

    @staticmethod
    def named_replace(value, **replacements):
        for key, replacement in replacements.items():
            value = value.replace(f"%%{key}%%", str(replacement))
        return value

    @staticmethod
    def format_float(value):
        return f'{value:,.2f}'

    @staticmethod
    def add_days(date, number_of_days):
        return date + timedelta(days=number_of_days)

    @staticmethod
    def markdown_to_html(md_content):
        html_content = markdown.markdown(md_content)
        return html_content

    def convert_html_to_pdf(self, source_html, output_filename):
        # open output file for writing (truncated binary)
        result_file = open(output_filename, "w+b")

        # convert HTML to PDF
        pisa_status = pisa.CreatePDF(
            source_html,  # the HTML to convert
            path=str(self.path_to_template / 'fonts'),
            dest=result_file
        )  # file handle to receive result

        # close output file
        result_file.close()  # close output file

        # return False on success and True on errors
        return pisa_status.err
