package TestingSystem;
import Common.Global;
import Common.Utils.Utils;
import GlobalData.Machine.Machine;
import GlobalData.User.User;
import Repository.EmailMessage;
import Repository.Server.ServerCode;
import Repository.Server.ServerExchangeUnit_2021;
import SapforTestingSystem.SapforTasksPackage.SapforTasksPackage;
import SapforTestingSystem.SapforTasksPackageSupervisor.SapforTasksPackageSupervisor;
import TestingSystem.Tasks.TestCompilationTask;
import TestingSystem.Tasks.TestTask;
import TestingSystem.TasksPackage.TasksPackage;
import TestingSystem.TasksPackage.TasksPackageState;
import TestingSystem.TestsSupervisor_2022.TestsSupervisor_2022;
import Visual_DVM_2021.Passes.PassException;
import Visual_DVM_2021.Passes.SSH.ConnectionPass;
import Visual_DVM_2021.Passes.TestingSystemPass;
import javafx.util.Pair;

import java.io.File;
import java.io.FileWriter;
import java.io.Serializable;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Vector;

import static TestingSystem.TasksDatabase.tests_db_name;
public class TestingPlanner {
    public String email;
    TasksPackage tasksPackage;
    TestsSupervisor_2022 supervisor;
    LinkedHashMap<String, Machine> machines = new LinkedHashMap<>();
    LinkedHashMap<String, User> users = new LinkedHashMap<>();
    protected Machine machine = null;
    protected User user = null;
    public LinkedHashMap<Long, TestCompilationTask> packageTasks = new LinkedHashMap<>();
    //----------
    SapforTasksPackage sapforTasksPackage = null;
    //----------
    public void UpdateTask(TestTask task_in) throws Exception {
        task_in.ChangeDate = new Date().getTime();
        ServerCommand(ServerCode.EditAccountObject, task_in);
    }
    public void UpdatePackage() throws Exception {
        tasksPackage.ChangeDate = new Date().getTime();
        ServerCommand(ServerCode.EditAccountObject, tasksPackage);
        //---------------
        if ((tasksPackage.needsEmail == 1) &&
                (tasksPackage.state.equals(TasksPackageState.PackageStart) ||
                        (tasksPackage.state.equals(TasksPackageState.Done)) ||
                        (tasksPackage.state.equals(TasksPackageState.Aborted))
                )) {
            EmailMessage message = new EmailMessage();
            message.subject = "Состояние пакета задач " + Utils.Brackets(tasksPackage.id) + " изменилось на " + Utils.Brackets(tasksPackage.state.getDescription());
            message.text = tasksPackage.summary;
            message.targets.add(email);
            ServerCommand(ServerCode.Email, message);
        }
    }
    //-
    public Object ServerCommand(ServerCode code_in, String arg, Serializable object_in) throws Exception {
        TestingSystemPass<Object> pass = new TestingSystemPass<Object>() {
            @Override
            public String getDescription() {
                return "";
            }
            @Override
            protected void ServerAction() throws Exception {
                Command(new ServerExchangeUnit_2021(code_in, arg, object_in));
                target = response.object;
            }
        };
        if (!pass.Do()) throw new PassException("Ошибка взаимодействия с сервером " + code_in);
        return pass.target;
    }
    public Object ServerCommand(ServerCode code_in, Serializable object_in) throws Exception {
        return ServerCommand(code_in, email, object_in);
    }
    Object ServerCommand(ServerCode code_in) throws Exception {
        return ServerCommand(code_in, email, null);
    }
    //-
    boolean isPrintOn() {
        return true;
    }
    public void Print(String message) {
        try {
            FileWriter testLog = new FileWriter(getClass().getSimpleName() + "_Log.txt", true);
            String dmessage = Utils.Brackets(new Date()) + " " + message;
            if (isPrintOn())
                System.out.println(dmessage);
            testLog.write(dmessage + "\n");
            testLog.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    boolean CheckConnection(Machine machine, User user) {
        //каждый раз соединяемся по новой. из за проблем с Exists.
        // к тому же, теперь задачи гоняет модуль, тут только проверка
        //так что время на разрыв уже не критично.
        try {
            user.connection = null;
            user.connection = new UserConnection(machine, user);
            Print("Соединение c " + machine.getURL() + " " + user.login + " успешно установлено.");
            user.connection.ShellCommand("ulimit -s unlimited"); // нужно, для запуска сишной части.
        } catch (Exception ex) {
            Global.Log.PrintException(ex);
            user.connection = null;
            Print("Не удалось установить соединение.");
        }
        return user.connection != null;
    }
    //-
    public void Perform() {
        Vector<String> emails = new Vector<>();
        while (true) {
            emails.clear();
            try {
                File[] accountsBases_ = Global.DataDirectory.listFiles(pathname ->
                        pathname.isFile() &&
                                Utils.getExtension(pathname).equals("sqlite") &&
                                !Utils.getNameWithoutExtension(pathname.getName()).isEmpty() &&
                                !pathname.getName().equals(tests_db_name + ".sqlite")
                );
                if (accountsBases_ != null) {
                    for (File accountBase : accountsBases_) {
                        String fileName = accountBase.getName();
                        String account_email = accountBase.getName().substring(0, fileName.lastIndexOf('_'));
                        emails.add(account_email);
                    }
                    for (String current_email : emails)
                        emailPass(current_email);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                try {
                    Utils.sleep(getSleepMillis());
                } catch (Exception ignored) {
                }
            }
        }
    }
    protected int getSleepMillis() {
        return 2000;
    }
    void emailPass(String email_in) {
        email = email_in;
        try {
            // System.out.println(email+" testing planner starts...");
            Pair<TasksPackage, LinkedHashMap<Long, TestCompilationTask>> p = (Pair<TasksPackage, LinkedHashMap<Long, TestCompilationTask>>) ServerCommand(ServerCode.GetFirstActiveAccountPackage);
            sapforTasksPackage = (SapforTasksPackage) ServerCommand(ServerCode.GetFirstActiveSapforTasksPackage);
            tasksPackage = null;
            packageTasks = null;
            tasksPackage = p.getKey();
            packageTasks = p.getValue();
            if (tasksPackage != null) {
                //  System.out.println("found dvm package: "+sapforTasksPackage.id);
                String machine_url = tasksPackage.machine_address + ":" + tasksPackage.machine_port;
                if (!machines.containsKey(machine_url))
                    machines.put(machine_url, new Machine(
                            tasksPackage.machine_name,
                            tasksPackage.machine_address,
                            tasksPackage.machine_port,
                            tasksPackage.machine_type));
                if (!users.containsKey(tasksPackage.user_name))
                    users.put(tasksPackage.user_name,
                            new User(tasksPackage.user_name, tasksPackage.user_password, tasksPackage.user_workspace));
                machine = machines.get(machine_url);
                //-->>
                user = users.get(tasksPackage.user_name);
                if (CheckConnection(machine, user)) {
                    try {
                        supervisor = new TestsSupervisor_2022(this, user.connection, tasksPackage, new Vector<>(packageTasks.values()));
                        supervisor.Perform();
                    } catch (Exception ex) {
                        Print("Ошибка сеанса, соединение будет разорвано.");
                        Print(ex.getMessage());
                        if (user.connection != null) {
                            user.connection.Disconnect();
                            user.connection = null;
                        }
                    }
                }
            }
            if (sapforTasksPackage != null) {
                System.out.println("found sapfor package: " + sapforTasksPackage.id + " state = " + sapforTasksPackage.state);
                try {
                    (new SapforTasksPackageSupervisor(this, sapforTasksPackage)).Perform();
                } catch (Exception ex) {
                    Print("Исключение при тестировании SAPROR");
                    Print(ex.getMessage());
                }
            }
        } catch (Exception ex) {
            Global.Log.PrintException(ex);
        }
    }
    public String getStarter() {
        return String.join("/", user.workspace, ConnectionPass.modules, ConnectionPass.starter);
    }
    public String getLauncher() {
        return String.join("/", user.workspace, ConnectionPass.modules, ConnectionPass.launcher);
    }
    public String getPlanner() {
        return String.join("/", user.workspace, ConnectionPass.modules, ConnectionPass.planner);
    }
    //--
    public void UpdateSapforPackage() throws Exception {
        sapforTasksPackage.ChangeDate = new Date().getTime();
        EmailMessage message = null;
        ServerCommand(ServerCode.EditAccountObject, sapforTasksPackage);
        if (sapforTasksPackage.needsEmail == 1) {
            switch (sapforTasksPackage.state) {
                case RunningExecution:
                case Aborted:
                    message = new EmailMessage();
                    message.subject = "Состояние пакета задач SAPFOR" + Utils.Brackets(sapforTasksPackage.id) + " изменилось на " + Utils.Brackets(sapforTasksPackage.state.getDescription());
                    break;
                case Done:
                    //результаты.
                    message = new EmailMessage();
                    message.subject = "Состояние пакета задач SAPFOR" + Utils.Brackets(sapforTasksPackage.id) + " изменилось на " + Utils.Brackets(sapforTasksPackage.state.getDescription());
                    message.text = sapforTasksPackage.summary;
                    break;
                default:
                    break;
            }
        }
        if (message != null) {
            message.targets.add(email);
            ServerCommand(ServerCode.Email, message);
        }
    }
}
