import os
import shutil
from tempfile import mkdtemp
from typing import Dict, List, Optional

from jinja2 import Environment, FileSystemLoader

from gentexdoc import PROGRAM_ID, processing
from gentexdoc.builtin import create_builtin_context
from gentexdoc.util import get_filename_without_extension, call


def generate_latex(template_file: str, context: Dict, output_file: str):
    env = Environment(loader=FileSystemLoader(searchpath="./"))
    result = env.get_template(template_file).render(**context)

    with open(output_file, "w") as output_fd:
        output_fd.write(result)


def generate_pdf(template_file: str, input_files: List[str], output_file: Optional[str] = None, force: bool = False, context: Optional[Dict] = None, verbose: bool = False) -> bool:
    if not os.path.exists(template_file):
        raise FileNotFoundError("The specified template file does not exist: " + template_file)

    # Naming the output file
    if output_file is None:
        if len(input_files) == 1:
            output_file = get_filename_without_extension(input_files[0]) + ".pdf"
        else: output_file = get_filename_without_extension(template_file) + ".pdf"

    if os.path.exists(output_file):
        if force:
            os.remove(output_file)
        else:
            print(f"Error: Output file '{output_file}' already exists")
            return False

    # Register builtin variables
    create_builtin_context(context)

    # Parsing input files
    for input_file in input_files:
        if not os.path.exists(input_file):
            raise FileNotFoundError("The specified input file does not exist: " + input_file)

        print(f"Parsing input markdown file '{input_file}'...")
        with open(input_file, "r") as input_fd:
            input_md = input_fd.read()
        processing.parse_context(context, input_md)

    tmpdir = mkdtemp(prefix=f"{PROGRAM_ID}-")
    try:
        # Converting context to latex
        context = processing.process_context(context, tmpdir, verbose)

        # Processing resulting tex file
        print("Generating output tex file...")
        latex_file = os.path.join(tmpdir, f"{PROGRAM_ID}.result.tex")
        generate_latex(template_file, context, latex_file)

        # Generating PDF file
        print("Generating PDF file...")
        pdf_file = os.path.join(tmpdir, f"{PROGRAM_ID}.result.pdf")  # Generated by XeLaTeX
        error = False

        if call(["xelatex", "-output-directory", tmpdir, latex_file], verbose) != 0:
            error = True
        if not error and call(["xelatex", "-output-directory", tmpdir, latex_file], verbose) != 0:  # We need to call xelatex twice in order for the table of contents to generate properly (when it exists)
            error = True

        if not error:
            shutil.move(pdf_file, output_file)
            print(f"'{output_file}' has been generated successfully")
            return True
        else:
            print(f"Error: Unable to generate PDF file")
            return False
    finally:
        shutil.rmtree(tmpdir)
