#!/usr/bin/python3

# Copyright (C) 2019 The Android Open Source Project
#
# Licensed 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 hashlib
import os
import shutil
import time

from abc import ABC, abstractmethod
from zipfile import ZipFile

import requests

from .reindex import IndexType, get_index_type
from ..constants import SITE_PATH, SITE_PLUGIN_PATH, SITE_LIB_PATH
from ..helpers import log
from ..config.cluster_mode import ClusterMode

LOG = log.get_logger("init")
MAX_LOCK_LIFETIME = 60
MAX_CACHED_VERSIONS = 5

REQUIRED_PLUGINS = ["healthcheck"]
REQUIRED_HA_PLUGINS = ["high-availability"]
REQUIRED_HA_LIBS = ["high-availability", "global-refdb"]
REQUIRED_MULTISITE_LIBS = [
    "events-broker",
    "global-refdb",
    "multi-site",
    "pull-replication",
]
REQUIRED_MULTISITE_PLUGINS = [
    "events-kafka",
    "multi-site",
    "pull-replication",
    "websession-broker",
]


class InvalidPluginException(Exception):
    """Exception to be raised, if the downloaded plugin is not valid."""


class MissingRequiredPluginException(Exception):
    """Exception to be raised, if the downloaded plugin is not valid."""


class AbstractPluginInstaller(ABC):
    def __init__(self, gerrit_config, config):
        self.gerrit_config = gerrit_config
        self.config = config

        self.required_plugins = self._get_required_plugins()
        self.required_libs = self._get_required_libs()

        self.plugins_changed = False

    def _create_plugins_dir(self):
        if not os.path.exists(SITE_PLUGIN_PATH):
            os.makedirs(SITE_PLUGIN_PATH)
            LOG.info("Created plugin installation directory: %s", SITE_PLUGIN_PATH)

    def _create_lib_dir(self):
        if not os.path.exists(SITE_LIB_PATH):
            os.makedirs(SITE_LIB_PATH)
            LOG.info("Created lib installation directory: %s", SITE_LIB_PATH)

    def _get_installed_plugins(self):
        return self._get_installed_jars(SITE_PLUGIN_PATH)

    def _get_installed_libs(self):
        return self._get_installed_jars(SITE_LIB_PATH)

    @staticmethod
    def _get_installed_jars(dir):
        if os.path.exists(dir):
            return [f for f in os.listdir(dir) if f.endswith(".jar")]

        return []

    def _get_required_plugins(self):
        required = REQUIRED_PLUGINS.copy()
        if self.config.is_ha:
            required.extend(REQUIRED_HA_PLUGINS)
        elif self.config.cluster_mode == ClusterMode.MULTISITE:
            required.extend(REQUIRED_MULTISITE_PLUGINS)
        if self.config.refdb:
            required.append(f"{self.config.refdb}-refdb")
        if get_index_type(self.gerrit_config) == IndexType.ELASTICSEARCH:
            required.append("index-elasticsearch")
        LOG.info(
            "Requiring plugins (ClusterMode: %s): %s",
            self.config.cluster_mode.name,
            required,
        )
        return required

    def _get_required_libs(self):
        required = []
        if self.config.is_ha:
            required.extend(REQUIRED_HA_LIBS)
        elif self.config.cluster_mode == ClusterMode.MULTISITE:
            required.extend(REQUIRED_MULTISITE_LIBS)
        elif self.config.refdb:
            required.append("global-refdb")
        if get_index_type(self.gerrit_config) == IndexType.ELASTICSEARCH:
            required.append("index-elasticsearch")
        LOG.info(
            "Requiring libs (ClusterMode: %s): %s",
            self.config.cluster_mode.name,
            required,
        )
        return required

    def _install_required_plugins(self):
        for plugin in self.required_plugins:
            if plugin in self.config.get_plugin_names():
                continue

            self._install_required_jar(plugin, SITE_PLUGIN_PATH)

    def _install_required_libs(self):
        for lib in self.required_libs:
            if lib in self.config.get_lib_names():
                continue

            self._install_required_jar(lib, SITE_LIB_PATH)

    def _install_required_jar(self, jar, target_dir):
        with ZipFile("/var/war/gerrit.war", "r") as war:
            # Lib modules can be packaged as a plugin. However, they could
            # currently not be installed by the init pgm tool.
            if f"WEB-INF/plugins/{jar}.jar" in war.namelist():
                self._install_plugin_from_war(jar, target_dir)
                return
        try:
            self._install_jar_from_container(jar, target_dir)
        except FileNotFoundError:
            raise MissingRequiredPluginException(f"Required jar {jar} was not found.")

    def _install_jar_from_container(self, plugin, target_dir):
        source_file = os.path.join("/var/plugins", plugin + ".jar")
        target_file = os.path.join(target_dir, plugin + ".jar")
        LOG.info(
            "Installing plugin %s from container to %s.",
            plugin,
            target_file,
        )
        if not os.path.exists(source_file):
            raise FileNotFoundError(
                "Unable to find required plugin in container: " + plugin
            )
        if os.path.exists(target_file) and self._get_file_sha(
            source_file
        ) == self._get_file_sha(target_file):
            return

        shutil.copyfile(source_file, target_file)
        self.plugins_changed = True

    def _install_plugins_from_war(self):
        for plugin in self.config.get_packaged_plugins():
            self._install_plugin_from_war(plugin["name"], SITE_PLUGIN_PATH)

    def _install_plugin_from_war(self, plugin, target_dir):
        LOG.info("Installing packaged plugin %s.", plugin)
        with ZipFile("/var/war/gerrit.war", "r") as war:
            war.extract(f"WEB-INF/plugins/{plugin}.jar", SITE_PLUGIN_PATH)

        source_file = f"{SITE_PLUGIN_PATH}/WEB-INF/plugins/{plugin}.jar"
        target_file = os.path.join(target_dir, f"{plugin}.jar")
        if not os.path.exists(target_file) or self._get_file_sha(
            source_file
        ) != self._get_file_sha(target_file):
            os.rename(source_file, target_file)
            self.plugins_changed = True

        shutil.rmtree(os.path.join(SITE_PLUGIN_PATH, "WEB-INF"), ignore_errors=True)

    @staticmethod
    def _get_file_sha(file):
        file_hash = hashlib.sha1()
        with open(file, "rb") as f:
            while True:
                chunk = f.read(64000)
                if not chunk:
                    break
                file_hash.update(chunk)

        LOG.debug("SHA1 of file '%s' is %s", file, file_hash.hexdigest())

        return file_hash.hexdigest()

    def _remove_unwanted_plugins(self):
        wanted_plugins = list(self.config.get_plugins())
        wanted_plugins.extend(self.required_plugins)
        self._remove_unwanted(
            wanted_plugins, self._get_installed_plugins(), SITE_PLUGIN_PATH
        )

    def _remove_unwanted_libs(self):
        wanted_libs = list(self.config.get_libs())
        wanted_libs.extend(self.required_libs)
        wanted_libs.extend(self.config.get_plugins_installed_as_lib())
        self._remove_unwanted(wanted_libs, self._get_installed_libs(), SITE_LIB_PATH)

    @staticmethod
    def _remove_unwanted(wanted, installed, dir):
        for plugin in installed:
            if os.path.splitext(plugin)[0] not in wanted:
                os.remove(os.path.join(dir, plugin))
                LOG.info("Removed plugin %s", plugin)

    def _symlink_plugins_to_lib(self):
        if not os.path.exists(SITE_LIB_PATH):
            os.makedirs(SITE_LIB_PATH)
        else:
            for f in os.listdir(SITE_LIB_PATH):
                path = os.path.join(SITE_LIB_PATH, f)
                if (
                    os.path.islink(path)
                    and os.path.splitext(f)[0]
                    not in self.config.get_plugins_installed_as_lib()
                ):
                    os.unlink(path)
                    LOG.info("Removed symlink %s", f)
        for lib in self.config.get_plugins_installed_as_lib():
            plugin_path = os.path.join(SITE_PLUGIN_PATH, f"{lib}.jar")
            if os.path.exists(plugin_path):
                try:
                    os.symlink(plugin_path, os.path.join(SITE_LIB_PATH, f"{lib}.jar"))
                except FileExistsError:
                    continue
            else:
                raise FileNotFoundError(
                    f"Could not find plugin {lib} to symlink to lib-directory."
                )

    def execute(self):
        self._create_plugins_dir()
        self._create_lib_dir()

        self._remove_unwanted_plugins()
        self._remove_unwanted_libs()

        self._install_required_plugins()
        self._install_required_libs()

        self._install_plugins_from_war()

        for plugin in self.config.get_downloaded_plugins():
            self._install_plugin(plugin)

        for plugin in self.config.get_libs():
            self._install_lib(plugin)

        self._symlink_plugins_to_lib()

    def _download_plugin(self, plugin, target):
        LOG.info("Downloading %s plugin to %s", plugin["name"], target)
        try:
            response = requests.get(plugin["url"])
        except requests.exceptions.SSLError:
            response = requests.get(plugin["url"], verify=self.config.ca_cert_path)

        with open(target, "wb") as f:
            f.write(response.content)

        file_sha = self._get_file_sha(target)

        if file_sha != plugin["sha1"]:
            os.remove(target)
            raise InvalidPluginException(
                (
                    f"SHA1 of downloaded file ({file_sha}) did not match "
                    f"expected SHA1 ({plugin['sha1']}). "
                    f"Removed downloaded file ({target})"
                )
            )

    def _install_plugin(self, plugin):
        self._install_jar(plugin, SITE_PLUGIN_PATH)

    def _install_lib(self, lib):
        self._install_jar(lib, SITE_LIB_PATH)

    @abstractmethod
    def _install_jar(self, plugin, target_dir):
        pass


class PluginInstaller(AbstractPluginInstaller):
    def _install_jar(self, plugin, target_dir):
        target = os.path.join(target_dir, f"{plugin['name']}.jar")
        if os.path.exists(target) and self._get_file_sha(target) == plugin["sha1"]:
            return

        self._download_plugin(plugin, target)

        self.plugins_changed = True


class CachedPluginInstaller(AbstractPluginInstaller):
    @staticmethod
    def _cleanup_cache(plugin_cache_dir):
        cached_files = [
            os.path.join(plugin_cache_dir, f) for f in os.listdir(plugin_cache_dir)
        ]
        while len(cached_files) > MAX_CACHED_VERSIONS:
            oldest_file = min(cached_files, key=os.path.getctime)
            LOG.info(
                "Too many cached files in %s. Removing file %s",
                plugin_cache_dir,
                oldest_file,
            )
            os.remove(oldest_file)
            cached_files.remove(oldest_file)

    @staticmethod
    def _create_download_lock(lock_path):
        with open(lock_path, "w", encoding="utf-8") as f:
            f.write(os.environ["HOSTNAME"])
            LOG.debug("Created download lock %s", lock_path)

    @staticmethod
    def _create_plugin_cache_dir(plugin_cache_dir):
        if not os.path.exists(plugin_cache_dir):
            os.makedirs(plugin_cache_dir)
            LOG.info("Created cache directory %s", plugin_cache_dir)

    def _get_cached_plugin_path(self, plugin):
        return os.path.join(
            self.config.plugin_cache_dir,
            plugin["name"],
            f"{plugin['name']}-{plugin['sha1']}.jar",
        )

    def _install_from_cache_or_download(self, plugin, target):
        cached_plugin_path = self._get_cached_plugin_path(plugin)

        if os.path.exists(cached_plugin_path):
            LOG.info("Installing %s plugin from cache.", plugin["name"])
        else:
            LOG.info("%s not found in cache. Downloading it.", plugin["name"])
            self._create_plugin_cache_dir(os.path.dirname(cached_plugin_path))

            lock_path = f"{cached_plugin_path}.lock"
            while os.path.exists(lock_path):
                LOG.info(
                    "Download lock found (%s). Waiting %d seconds for it to be released.",
                    lock_path,
                    MAX_LOCK_LIFETIME,
                )
                lock_timestamp = os.path.getmtime(lock_path)
                if time.time() > lock_timestamp + MAX_LOCK_LIFETIME:
                    LOG.info("Stale download lock found (%s).", lock_path)
                    self._remove_download_lock(lock_path)

            self._create_download_lock(lock_path)

            try:
                self._download_plugin(plugin, cached_plugin_path)
            finally:
                self._remove_download_lock(lock_path)

        shutil.copy(cached_plugin_path, target)
        self._cleanup_cache(os.path.dirname(cached_plugin_path))

    def _install_jar(self, plugin, target_dir):
        install_path = os.path.join(target_dir, f"{plugin['name']}.jar")
        if (
            os.path.exists(install_path)
            and self._get_file_sha(install_path) == plugin["sha1"]
        ):
            return

        self.plugins_changed = True
        self._install_from_cache_or_download(plugin, install_path)

    @staticmethod
    def _remove_download_lock(lock_path):
        os.remove(lock_path)
        LOG.debug("Removed download lock %s", lock_path)


def get_installer(gerrit_config, config):
    plugin_installer = (
        CachedPluginInstaller if config.plugin_cache_enabled else PluginInstaller
    )
    return plugin_installer(gerrit_config, config)
