import os.path
import string
import datetime
import logging

import subprocess
import tempfile
import shutil

logger = logging.getLogger(__name__)


class Environment:
    def __init__(self):
        self.tex_kpsewhich_path = None
        #self.tex_distribution_path = None

    def find_executable(self, exe_name):
        from distutils.spawn import find_executable
        x = find_executable(exe_name)
        if not x:
            raise RuntimeError(
                f"Could not locate executable ‘{x}’. Please set PATH accordingly."
            )
        return x

    def _ensure_tex_kpsewhich_path(self):
        # find TeX distribution path
        if self.tex_kpsewhich_path is None:
            self.tex_kpsewhich_path = self.find_executable('kpsewhich')

    def kpsewhich(self, fname):
        self._ensure_tex_kpsewhich_path()
        try:
            output = subprocess.check_output(
                args=[self.tex_kpsewhich_path, fname],
                input=None,
            ).decode('utf-8').strip()
            return output
        except subprocess.CalledProcessError as e:
            logger.error("kpsewhich failed: %s", e)
            raise RuntimeError(
                f"Unable to locate file {fname} via TeX' kpsewhich"
            )



_tmpl_header = string.Template(r"""\NeedsTeXFormat{$BUNDLELATEXFORMAT}
\ProvidesPackage{$BUNDLEPACKAGENAME}[$BUNDLEPACKAGEDATE $BUNDLEPACKAGEVERSION]
%% Begin styxpress <$BUNDLEPACKAGENAME>
""")

_tmpl_footer = string.Template(r"""%% End styxpress <$BUNDLEPACKAGENAME>""" + "\n")

STYXPRESS_COMMENT_TEST = '%%% STYXPRESS'

AUTOGEN_WARNING_COMMENT = \
    r''': THIS FILE IS AUTOMATICALLY GENERATED -- CHANGES WILL BE OVERWRITTEN %%%
%%% See https://github.com/phfaist/styxpress'''



class TargetBundle:
    def __init__(self, environment, styxpress_folder, package_name):

        self.environment = environment
        self.styxpress_folder = styxpress_folder

        self.bundle_package_name = package_name
        self.bundle_latex_format = 'LaTeX2e'
        self.bundle_package_date = datetime.datetime.now().strftime('%Y/%m/%d')
        self.bundle_package_version = 'v0.1.0'

        self.bundle_use_styxpress_comment = True
        self.bundle_styxpress_comment_text = AUTOGEN_WARNING_COMMENT

        self._embeds = []

    def resolve_file_name(self, filename):
        return os.path.join(self.styxpress_folder, filename)

    def add_embed(self, embed_engine, config):

        from ._resolve_engine import resolve_embed_engine

        embed_engine_cls = resolve_embed_engine(embed_engine)
        # create embed engine instance
        instance = embed_engine_cls(self, config)

        self._embeds.append( {
            'embed_engine': embed_engine,
            'embed_engine_cls': embed_engine_cls,
            'config': config,
            '_instance': instance
        } )

    def get_initial_comment(self):
        if not self.bundle_use_styxpress_comment:
            return ''

        return STYXPRESS_COMMENT_TEST + self.bundle_styxpress_comment_text + '\n'

    def get_header(self):
        return _tmpl_header.substitute( **self._tmpl_subst() )

    def get_footer(self):
        return _tmpl_footer.substitute( **self._tmpl_subst() )

    def generate(self, output_dir):

        foutname = os.path.join(output_dir, self.bundle_package_name + '.sty')

        if os.path.exists(foutname):
            # check that it was previously autogenerated by styxpress and that
            # we're not accidentally overwriting a different STY file.
            with open(foutname, 'r') as f:
                first_line = f.readline(len(STYXPRESS_COMMENT_TEST))
            if not first_line.startswith(STYXPRESS_COMMENT_TEST):
                msg = (f"File ‘{foutname}’ exists and does not appear to have "
                       f"been generated by ‘styxpress’.  If you're sure you want "
                       f"to overwrite it, please delete it first.")
                logger.error(msg)
                raise RuntimeError(msg)

            # logger.error(f"File ‘{foutname}’ exists, sorry I'm not confident enough "
            #              f"to overwrite it. Please delete it first.")
            # raise RuntimeError(f"File ‘{foutname}’ exists")


        # First we output to a temporary file, then copy its contents to the
        # target file.  This is because if there is an error while processing
        # the embeds, we don't want to have written to the target file yet.

        with tempfile.TemporaryFile(mode='w+') as f:

            f.write( self.get_initial_comment() )

            f.write( self.get_header() )

            for d in self._embeds:
                d['_instance'].embed(f)

            f.write( self.get_footer() )

            f.seek(0)

            # all right, now copy everything to the output file.
            with open(foutname, 'w') as ftarget:
                shutil.copyfileobj(f, ftarget)


    def _tmpl_subst(self):
        return dict(
            BUNDLELATEXFORMAT=self.bundle_latex_format,
            BUNDLEPACKAGENAME=self.bundle_package_name,
            BUNDLEPACKAGEDATE=self.bundle_package_date,
            BUNDLEPACKAGEVERSION=self.bundle_package_version,
        )


import os.path
import string
import datetime
import logging

import subprocess
import tempfile
import shutil

logger = logging.getLogger(__name__)


class Environment:
    def __init__(self):
        self.tex_kpsewhich_path = None
        #self.tex_distribution_path = None

    def find_executable(self, exe_name):
        from distutils.spawn import find_executable
        x = find_executable(exe_name)
        if not x:
            raise RuntimeError(
                f"Could not locate executable ‘{x}’. Please set PATH accordingly."
            )
        return x

    def _ensure_tex_kpsewhich_path(self):
        # find TeX distribution path
        if self.tex_kpsewhich_path is None:
            self.tex_kpsewhich_path = self.find_executable('kpsewhich')

    def kpsewhich(self, fname):
        self._ensure_tex_kpsewhich_path()
        try:
            output = subprocess.check_output(
                args=[self.tex_kpsewhich_path, fname],
                input=None,
            ).decode('utf-8').strip()
            return output
        except subprocess.CalledProcessError as e:
            logger.error("kpsewhich failed: %s", e)
            raise RuntimeError(
                f"Unable to locate file {fname} via TeX' kpsewhich"
            )



_tmpl_header = string.Template(r"""\NeedsTeXFormat{$BUNDLELATEXFORMAT}
\ProvidesPackage{$BUNDLEPACKAGENAME}[$BUNDLEPACKAGEDATE $BUNDLEPACKAGEVERSION]
%% Begin styxpress <$BUNDLEPACKAGENAME>
""")

_tmpl_footer = string.Template(r"""%% End styxpress <$BUNDLEPACKAGENAME>""" + "\n")

STYXPRESS_COMMENT_TEST = '%%% STYXPRESS'

AUTOGEN_WARNING_COMMENT = \
    r''': THIS FILE IS AUTOMATICALLY GENERATED -- CHANGES WILL BE OVERWRITTEN %%%
%%% See https://github.com/phfaist/styxpress'''



class TargetBundle:
    def __init__(self, environment, styxpress_folder, package_name):

        self.environment = environment
        self.styxpress_folder = styxpress_folder

        self.bundle_package_name = package_name
        self.bundle_latex_format = 'LaTeX2e'
        self.bundle_package_date = datetime.datetime.now().strftime('%Y/%m/%d')
        self.bundle_package_version = 'v0.1.0'

        self.bundle_use_styxpress_comment = True
        self.bundle_styxpress_comment_text = AUTOGEN_WARNING_COMMENT

        self._embeds = []

    def resolve_file_name(self, filename):
        return os.path.join(self.styxpress_folder, filename)

    def add_embed(self, embed_engine, config):

        from ._resolve_engine import resolve_embed_engine

        embed_engine_cls = resolve_embed_engine(embed_engine)
        # create embed engine instance
        instance = embed_engine_cls(self, config)

        self._embeds.append( {
            'embed_engine': embed_engine,
            'embed_engine_cls': embed_engine_cls,
            'config': config,
            '_instance': instance
        } )

    def get_initial_comment(self):
        if not self.bundle_use_styxpress_comment:
            return ''

        return STYXPRESS_COMMENT_TEST + self.bundle_styxpress_comment_text + '\n'

    def get_header(self):
        return _tmpl_header.substitute( **self._tmpl_subst() )

    def get_footer(self):
        return _tmpl_footer.substitute( **self._tmpl_subst() )

    def generate(self, output_dir):

        foutname = os.path.join(output_dir, self.bundle_package_name + '.sty')

        if os.path.exists(foutname):
            # check that it was previously autogenerated by styxpress and that
            # we're not accidentally overwriting a different STY file.
            with open(foutname, 'r') as f:
                first_line = f.readline(len(STYXPRESS_COMMENT_TEST))
            if not first_line.startswith(STYXPRESS_COMMENT_TEST):
                msg = (f"File ‘{foutname}’ exists and does not appear to have "
                       f"been generated by ‘styxpress’.  If you're sure you want "
                       f"to overwrite it, please delete it first.")
                logger.error(msg)
                raise RuntimeError(msg)

            # logger.error(f"File ‘{foutname}’ exists, sorry I'm not confident enough "
            #              f"to overwrite it. Please delete it first.")
            # raise RuntimeError(f"File ‘{foutname}’ exists")


        # First we output to a temporary file, then copy its contents to the
        # target file.  This is because if there is an error while processing
        # the embeds, we don't want to have written to the target file yet.

        with tempfile.TemporaryFile(mode='w+') as f:

            f.write( self.get_initial_comment() )

            f.write( self.get_header() )

            for d in self._embeds:
                d['_instance'].embed(f)

            f.write( self.get_footer() )

            f.seek(0)

            # all right, now copy everything to the output file.
            with open(foutname, 'w') as ftarget:
                shutil.copyfileobj(f, ftarget)


    def _tmpl_subst(self):
        return dict(
            BUNDLELATEXFORMAT=self.bundle_latex_format,
            BUNDLEPACKAGENAME=self.bundle_package_name,
            BUNDLEPACKAGEDATE=self.bundle_package_date,
            BUNDLEPACKAGEVERSION=self.bundle_package_version,
        )


#self.tex_distribution_path = None # find TeX distribution path \NeedsTeXFormat{$BUNDLELATEXFORMAT} \ProvidesPackage{$BUNDLEPACKAGENAME}[$BUNDLEPACKAGEDATE $BUNDLEPACKAGEVERSION] %% Begin styxpress <$BUNDLEPACKAGENAME> %% End styxpress <$BUNDLEPACKAGENAME> : THIS FILE IS AUTOMATICALLY GENERATED -- CHANGES WILL BE OVERWRITTEN %%% %%% See https://github.com/phfaist/styxpress # create embed engine instance # check that it was previously autogenerated by styxpress and that # we're not accidentally overwriting a different STY file. # logger.error(f"File ‘{foutname}’ exists, sorry I'm not confident enough " #              f"to overwrite it. Please delete it first.") # raise RuntimeError(f"File ‘{foutname}’ exists") # First we output to a temporary file, then copy its contents to the # target file.  This is because if there is an error while processing # the embeds, we don't want to have written to the target file yet. # all right, now copy everything to the output file.