import os

from systools import sys_parsefilepath

from application.model import UpdateType
from application.model.customexception import ErrorUpdatingStartStop
from application.service import UpdaterService
from application.util import (
    LoggerUtil,
    settings,
)

GENESIS_PATH = "../../genesis"

logger = LoggerUtil.get_logger_name(__name__)


class StartStopUpdaterService(object):
    def __init__(
        self,
        updater_service,  # type: UpdaterService
    ):
        # type: (...) -> None

        self.update_type = UpdateType.binaries
        self.update_name = self.update_type.name
        data_path = sys_parsefilepath("{HVDATADIR}")
        self.genesis_path = os.path.join(
            data_path,
            GENESIS_PATH,
        )
        self.updater_service = updater_service
        self.core_relative_linux_path = "linux-x86_64"
        self.core_relative_windows_path = "windows-x86"

    def update_start_stop(self):
        # type: (...) -> None

        if self._check_isdev():
            return

        settings.set_update_control(
            self.update_name,
            "$UPDATING_START_STOP_FILES",
        )
        genesis_bin_path_linux = os.path.join(
            self.genesis_path,
            "bin",
            self.core_relative_linux_path,
        )
        genesis_bin_path_windows = os.path.join(
            self.genesis_path,
            "bin",
            self.core_relative_windows_path,
        )
        try:
            logger.info("Updating start/stop files")
            if os.path.exists(genesis_bin_path_linux) and os.path.exists(genesis_bin_path_windows):
                genesis_root_path_linux = os.path.join(
                    self.genesis_path,
                    "root",
                    self.core_relative_linux_path,
                )
                genesis_root_path_windows = os.path.join(
                    self.genesis_path,
                    "root",
                    self.core_relative_windows_path,
                )

                files_to_root_folder = ["start_node", "stop", "E-Deploy POS"]
                files_to_pos_folder = ["start_server", "stop", "E-Deploy POS"]
                files_to_remove = ["start_node", "start_server", "stop", "E-Deploy POS"]

                for destination_path in [genesis_root_path_linux, genesis_root_path_windows]:
                    self.updater_service.create_dir(
                        path=destination_path,
                        delete_if_exists=False
                    )
                    self._start_stop_copy_process(
                        files_to_copy=files_to_root_folder,
                        original_path=genesis_bin_path_linux if self.core_relative_linux_path in destination_path else genesis_bin_path_windows,
                        destination_path=destination_path,
                        file_to_rename="start_node",
                    )

                pos_path = os.path.join(
                    self.genesis_path,
                    "..",
                    "",
                )
                self._start_stop_copy_process(
                    files_to_copy=files_to_pos_folder,
                    original_path=genesis_bin_path_windows if self._is_windows() else genesis_bin_path_linux,
                    destination_path=pos_path,
                    file_to_rename="start_server",
                )

                for genesis_bin_path in [genesis_bin_path_linux, genesis_bin_path_windows]:
                    for file_name in files_to_remove:
                        self._remove_file(
                            file_name=file_name,
                            path=genesis_bin_path,
                        )

            logger.info("Update start/stop successfully!")
        except Exception as _:
            logger.exception("Error updating start/stop")
            raise ErrorUpdatingStartStop()

    def has_genesis_root_path(
        self
    ):
        # type: () -> bool

        if self._check_isdev():
            return True

        genesis_root_path = os.path.join(self.genesis_path, "root")
        return os.path.exists(genesis_root_path)

    def _start_stop_copy_process(
        self,
        files_to_copy,     # type: list
        original_path,     # type: str
        destination_path,  # type: str
        file_to_rename,    # type: str
    ):
        # type: (...) -> None

        for file_name in files_to_copy:
            original_file_path = os.path.join(
                original_path,
                "{0}.{1}".format(
                    file_name,
                    self._get_extension(
                        file_name,
                        original_path,
                    ),
                ),
            )
            if os.path.exists(original_file_path):
                destination_file_name = file_name if file_name != file_to_rename else "start"
                self._remove_file(
                    file_name=destination_file_name,
                    path=destination_path,
                )

                self.updater_service.copy_file(
                    original_file_path=original_file_path,
                    destination_file_path=os.path.join(
                        destination_path,
                        "{0}.{1}".format(
                            destination_file_name,
                            self._get_extension(
                                destination_file_name,
                                destination_path,
                            ),
                        ),
                    ),
                )

    def _remove_file(
        self,
        file_name,  # type: str
        path,       # type: str
    ):
        # type: (...) -> None

        file_path = os.path.join(
            path,
            "{0}.{1}".format(
                file_name,
                self._get_extension(
                    file_name,
                    path,
                ),
            ),
        )
        if os.path.exists(file_path):
            os.remove(file_path)

    def _get_extension(
        self,
        file_name,  # type: str
        path=None,  # type: str
    ):
        # type: (...) -> str

        linux_extension = "sh"
        win_extension = "bat" if file_name != "E-Deploy POS" else "exe"
        so_extension = win_extension if self._is_windows() else linux_extension
        if path is None:
            return so_extension
        if self.core_relative_windows_path in path:
            return win_extension
        if self.core_relative_linux_path in path:
            return linux_extension
        return so_extension

    @staticmethod
    def _is_windows():
        # type: () -> bool

        return "win" in os.sys.platform

    @staticmethod
    def _check_isdev(
    ):
        # type: (...) -> bool

        return os.environ.get("DEBUG", "").upper() == "TRUE"

    @staticmethod
    def _search_in_file(
        file_path,             # type: str
        target,                # type: str
        line_scan_limit=None,  # type: int
    ):
        # type: (...) -> bool

        try:
            with open(file_path, 'r+') as f:
                scanned_line_counter = 0
                for line in f:
                    line = line.strip()
                    if target in line:
                        return True
                    if line_scan_limit is not None and scanned_line_counter >= line_scan_limit:
                        return False
                    scanned_line_counter += 1
        except Exception:
            return False
        return False
