# This file is part of the eseas project
# Copyright (C) 2024 Sermet Pekin
#
# This source code is free software; you can redistribute it and/or
# modify it under the terms of the European Union Public License
# (EUPL), Version 1.2, as published by the European Commission.
#
# You should have received a copy of the EUPL version 1.2 along with this
# program. If not, you can obtain it at:
# <https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12>.
#
# This source code is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# European Union Public License for more details.
#
# Alternatively, if agreed upon, you may use this code under any later
# version of the EUPL published by the European Commission.


import os
import platform
from dataclasses import dataclass
import subprocess
from pathlib import Path



def check_java_version():
    JAVA_EXEC_PATH = "/usr/bin/java"
    os.system(f"{JAVA_EXEC_PATH} -version")


def get_os():
    return str(platform.system()).lower()



@dataclass
class JavaEnviron:

    def __init__(self, java_bin: str = None, quick=None):
        self.java_bin = None if java_bin is None else str(java_bin)
        self.check_exists()

        self.separator = ";" if self.windows() else ":"
        self.quick = True if quick is None else False
        if self.java_bin:
            self.quick = False

        self.process()

    def check_exists(self):
        if self.java_bin is None:
            return
        p = Path(self.java_bin)
        if p.exists():
            return
        raise ValueError(
            f"""\n\n `java_bin` directory was given as `{self.java_bin}` but it does not exist or it is not a directory `{self.java_bin}`
                         if your java folder is already defined as `path` just remove java_bin parameter while calling Cruncher. 
                         Or give a correct folder where java executable exists. 
                         """
        )

    def process(self):
        if self.java_bin is None:
            self.show_java_version()
            self.show_cmd()
            self.check_java_folders()
        else:
            self.set_path()

            self.sleep(3)
            self.show_java_version()
            self.show_cmd()
            self.check_java_folders()

    def windows(self) -> bool:
        return get_os() == "windows"

    def find_java_paths(self) -> list[str]:
        # cmd_where_which = "where" if self.windows() else "which"
        # result = self.run_process([cmd_where_which, "-a", "java"])
        cmd_list = ["where", "java"] if self.windows() else ["which", "-a", "java"]
        result = self.run_process(cmd_list)
        java_paths = result.stdout.strip().split("\n")
        return java_paths if java_paths[0] else []

    def run_process(self, cmds):
        class Result:
            stderr = "Error in subprocess while running " + " ".join(cmds)
            stdout = ""

        result = Result()
        try:
            result = subprocess.run(cmds, capture_output=True, text=True)
        except Exception:
            import traceback

            traceback.print_exc()

        return result

    def sleep(self, num=2):
        if self.quick:
            return
        import time

        time.sleep(num)

    def show_java_version(self):
        print("[showing java version] ...")
        result = self.run_process(["java", "-version"])
        res = (str(result.stdout) + str(result.stderr)).strip().split("\n")
        msg = "\n".join(res)
        print("Java Version \n", msg)
        self.sleep(2)

    def check_java_folders(self):
        print("[checking Java folders] ...")
        java_executables: list = self.find_java_paths()
        folders = self.split()
        active = False
        suffix = "/java.exe" if self.windows() else "/java"
        active_java_folder = "None"
        potential_java_folders = []
        for path in java_executables:
            p = str(path).removesuffix(suffix)
            if p in folders:
                if active is False:
                    active = True
                    active_java_folder = p
                    potential_java_folders.append((True, p))
                else:
                    potential_java_folders.append((False, p))

        folders = self.split()
        liste = []
        for p in folders:
            bool_ = active_java_folder == p
            liste.append((bool_, p))

        self.show_folders(
            potential_java_folders, "Current Folders in environment [Path variable]"
        )

        self.sleep(2)
        return potential_java_folders

    def show_cmd(self):
        cmd = """
        To check manually :
        from Terminal type  
                echo $PATH 
                java -version 

            """
        if self.windows():
            cmd = """
        To check manually :
        from Command line 
                path
                java -version 
            """
        print(cmd)
        self.sleep(2)

    def split(self) -> tuple:
        d = os.environ.get("PATH")
        return d.split(self.separator)

    def show_folders(self, items: tuple, msg: str = None):
        if not items:
            return
        if msg is None:
            msg = "Setting path environment variable with these folders:"

        def p(bool_: bool, string: str):
            string = str(string)
            if bool_:
                return "[+]  -> " + string
            return "     -> " + string

        def show():
            template = msg
            print(template)
            for bool_, item in items:
                x = p(bool_, item)
                if item is None:
                    continue
                print(x)

        show()
        self.sleep(2)

    def set_path(self):
        folders = self.split()
        folders2 = [self.java_bin] + [x for x in folders if x != self.java_bin]

        def check(string):
            return string == str(self.java_bin)

        items2 = [(check(x), x) for x in folders2]
        self.show_folders(items2)
        os.environ["PATH"] = self.separator.join(folders2)

        print(f"[Done] {self.java_bin} was set as java folder")
        self.sleep(2)


# e = JavaEnviron("/usr/bin")
