#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you 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.

import logging
import os
import shutil
import subprocess
import tempfile


class ImageBuilder:
    """
    Builds an image from source code
    """

    __NO_CACHE = 'no_cache'

    def __init__(self, config, base_path, relative_source_path, tag):
        """
        :param config: task/service config
        :param base_path: directory containing liminal yml
        :param relative_source_path: source path relative to liminal yml
        :param tag: image tag
        """
        self.base_path = base_path
        self.relative_source_path = relative_source_path
        self.tag = tag
        self.config = config

    def build(self):
        """
        Builds source code into an image.
        """
        logging.info(f'[ ] Building image: {self.tag}')

        temp_dir = self.__temp_dir()

        self.__copy_source_code(temp_dir)
        self._write_additional_files(temp_dir)

        no_cache = ''
        if self.__NO_CACHE in self.config and self.config[self.__NO_CACHE]:
            no_cache = '--no-cache=true'

        docker = 'docker' if shutil.which('docker') is not None else '/usr/local/bin/docker'
        docker_build_command = f'{docker} build {no_cache} ' + \
                               f'--tag {self.tag} '

        docker_build_command += f'--progress=plain {self._build_flags()} '

        docker_build_command += f'{temp_dir}'

        if self._use_buildkit():
            docker_build_command = f'DOCKER_BUILDKIT=1 {docker_build_command}'

        logging.info(docker_build_command)

        docker_build_out = ''
        try:
            docker_build_out = subprocess.check_output(docker_build_command,
                                                       shell=True, stderr=subprocess.STDOUT,
                                                       timeout=240)
        except subprocess.CalledProcessError as e:
            docker_build_out = e.output
            raise e
        finally:
            logging.info('=' * 80)
            for line in str(docker_build_out)[2:-3].split('\\n'):
                logging.info(line)
            logging.info('=' * 80)

        self.__remove_dir(temp_dir)

        logging.info(f'[X] Building image: {self.tag} (Success).')

        return docker_build_out

    def __copy_source_code(self, temp_dir):
        self.__copy_dir(os.path.join(self.base_path, self.relative_source_path), temp_dir)

    def _write_additional_files(self, temp_dir):
        for file in [self._dockerfile_path()] + self._additional_files_from_paths():
            self.__copy_file(file, temp_dir)

        for filename, content in self._additional_files_from_filename_content_pairs():
            with open(os.path.join(temp_dir, filename), 'w') as file:
                file.write(content)

    def __temp_dir(self):
        temp_dir = tempfile.mkdtemp()
        # Delete dir for shutil.copytree to work
        self.__remove_dir(temp_dir)
        return temp_dir

    @staticmethod
    def __remove_dir(temp_dir):
        shutil.rmtree(temp_dir)

    @staticmethod
    def __copy_dir(source_path, destination_path):
        shutil.copytree(source_path, destination_path)

    @staticmethod
    def __copy_file(source_file_path, destination_file_path):
        shutil.copy2(source_file_path, destination_file_path)

    @staticmethod
    def _dockerfile_path():
        """
        Path to Dockerfile
        """
        raise NotImplementedError()

    @staticmethod
    def _additional_files_from_paths():
        """
        List of paths to additional files
        """
        return []

    def _additional_files_from_filename_content_pairs(self):
        """
        File name and content pairs to create files from
        """
        return []

    def _build_flags(self):
        """
        Additional build flags to add to docker build command.
        """
        return ''

    def _use_buildkit(self):
        """
        overwrite with True to use docker buildkit
        """
        return False


class ServiceImageBuilderMixin(object):
    pass
