package SapforTestingSystem.SapforTasksPackageSupervisor;
import Common.Constants;
import Common.Current;
import Common.Global;
import Common.GlobalProperties;
import Common.Utils.Utils;
import GlobalData.Tasks.TaskState;
import Repository.Server.ServerCode;
import SapforTestingSystem.Json.SapforConfiguration_json;
import SapforTestingSystem.Json.SapforTasksPackage_json;
import SapforTestingSystem.Json.SapforTasksResults_json;
import SapforTestingSystem.Json.SapforTest_json;
import SapforTestingSystem.SapforConfiguration.SapforConfiguration;
import SapforTestingSystem.SapforConfiguration.SapforConfigurationInterface;
import SapforTestingSystem.SapforTask.SapforTask;
import SapforTestingSystem.SapforTasksPackage.SapforTasksPackage;
import TestingSystem.Group.Group;
import TestingSystem.TasksPackage.TasksPackageState;
import TestingSystem.Test.Test;
import TestingSystem.TestingPlanner;
import Visual_DVM_2021.Passes.PassCode_2021;
import javafx.util.Pair;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Vector;
public class SapforTasksPackageSupervisor {
    protected TestingPlanner planner; //планировщик.
    SapforTasksPackage sapforTasksPackage = null;
    public SapforTasksPackageSupervisor(TestingPlanner planner_in, SapforTasksPackage sapforTasksPackage_in) {
        planner = planner_in;
        sapforTasksPackage = sapforTasksPackage_in;
    }
    private void TestsSynchronize() throws Exception {
        Vector<String> testsIds = new Vector<>(Arrays.asList(sapforTasksPackage.testsIds.split("\n")));
        Vector<String> configurationsIds = new Vector<>(Arrays.asList(sapforTasksPackage.configurationsIds.split("\n")));
        Vector<Object> tests_ = (Vector<Object>) planner.ServerCommand(ServerCode.GetObjectsCopiesByPK, "", new Pair<>(Test.class, testsIds));
        Vector<Object> configurations_ = (Vector<Object>) planner.ServerCommand(ServerCode.GetObjectsCopiesByPK, "", new Pair<>(SapforConfiguration.class, configurationsIds));
        LinkedHashMap<String, Test> tests = new LinkedHashMap<>();
        LinkedHashMap<String, SapforConfiguration> configurations = new LinkedHashMap<>();
        Vector<String> groupsIds = new Vector<>();
        LinkedHashMap<String, Group> groups = new LinkedHashMap<>();
        //--
        for (Object o : tests_) {
            Test test = (Test) o;
            System.out.println(test.description);
            tests.put(test.id, test);
            if (!groupsIds.contains(test.group_id))
                groupsIds.add(test.group_id);
        }
        //--
        Vector<Object> groups_ = (Vector<Object>) planner.ServerCommand(ServerCode.GetObjectsCopiesByPK, "", new Pair<>(Group.class, groupsIds));
        for (Object o : groups_) {
            Group group = (Group) o;
            System.out.println(group.description);
            groups.put(group.id, group);
        }
        //--
        for (Object o : configurations_) {
            SapforConfiguration sapforConfiguration = (SapforConfiguration) o;
            System.out.println(sapforConfiguration.id);
            configurations.put(sapforConfiguration.id, sapforConfiguration);
        }
        //--
        SapforTasksPackage_json package_json = new SapforTasksPackage_json();
        package_json.kernels = sapforTasksPackage.kernels;
        for (Test test : tests.values()) {
            SapforTest_json test_json = new SapforTest_json();
            test_json.test_description = test.description;
            test_json.group_description = groups.get(test.group_id).description;
            package_json.tests.add(test_json);
        }
        //создание рабочего пространства для пакетного режима
        File packageWorkspace = new File(Global.SapforPackagesDirectory, String.valueOf(sapforTasksPackage.id));
        Utils.CheckAndCleanDirectory(packageWorkspace);
        sapforTasksPackage.workspace = packageWorkspace.getAbsolutePath();
        //копирование тестов по конфигурациям.
        for (String configuration_id : configurationsIds) {
            SapforConfiguration configuration = configurations.get(configuration_id);
            //--
            SapforConfiguration_json configuration_json = new SapforConfiguration_json();
            configuration_json.id = String.valueOf(configuration_id);
            configuration_json.flags = SapforConfigurationInterface.getFlags(configuration);
            configuration_json.codes.add(PassCode_2021.SPF_CorrectCodeStylePass); //всегда добавляется.
            configuration_json.codes.addAll(SapforConfigurationInterface.getPassCodes(configuration));
            //--->>
            package_json.configurations.add(configuration_json);
            //-->>
            File configurationWorkspace = new File(packageWorkspace, configuration_id);
            FileUtils.forceMkdir(configurationWorkspace);
            for (String test_id : testsIds) {
                Test test = tests.get(test_id);
                File test_root = new File(configurationWorkspace, test.description);
                Utils.CheckAndCleanDirectory(test_root);
                FileUtils.copyDirectory(new File(Global.TestsDirectory, test.id), test_root);
            }
        }
        //копирование SAPFOR
        File sapforFile = new File(sapforTasksPackage.workspace, Utils.getDateName("SAPFOR_F"));
        FileUtils.copyFile(new File(sapforTasksPackage.sapfor_drv), sapforFile);
        if (!sapforFile.setExecutable(true))
            throw new Exception("Не удалось сделать файл " + sapforFile.getName() + " исполняемым!");
        sapforTasksPackage.sapfor_process_name = package_json.sapfor_drv = sapforFile.getName();
        //--->>
        //копирование визуализатора
        File visualiser = new File(sapforTasksPackage.workspace, "VisualSapfor.jar");
        FileUtils.copyFile(new File(Global.Home, "TestingSystem.jar"), visualiser);
        //создание настроек
        GlobalProperties properties = new GlobalProperties();
        properties.Mode = Current.Mode.Package;
        Utils.jsonToFile(properties, new File(sapforTasksPackage.workspace, "properties"));
        //создание инструкции
        File package_json_file = new File(sapforTasksPackage.workspace, "package_json");
        Utils.jsonToFile(package_json, package_json_file);
        //подготовка пакетного режима. Запустит его уже очередь.
        Utils.createScript(packageWorkspace, packageWorkspace, "start", "java -jar VisualSapfor.jar");
        //--
    }
    void PackageStart() throws Exception {
        System.out.println("start sapfor package " + sapforTasksPackage.id);
        File workspace = new File(sapforTasksPackage.workspace);
        File script = new File(sapforTasksPackage.workspace, "start");
        ProcessBuilder procBuilder = new ProcessBuilder(script.getAbsolutePath());
        procBuilder.directory(workspace);
        procBuilder.start();
        //--->>
        File started = new File(sapforTasksPackage.workspace, Constants.STARTED);
        while (!started.exists()) {
            System.out.println("waiting for package start...");
            Utils.sleep(1000);
        }
        //-->>
        sapforTasksPackage.state = TasksPackageState.RunningExecution;
        planner.UpdateSapforPackage();
        System.out.println("done");
    }
    void CheckPackageState() throws Exception {
        System.out.println("check sapfor package " + sapforTasksPackage.id);
        File done = new File(sapforTasksPackage.workspace, Constants.DONE);
        File aborted = new File(sapforTasksPackage.workspace, Constants.ABORTED);
        if (done.exists()) {
            sapforTasksPackage.state = TasksPackageState.Analysis;
            planner.UpdateSapforPackage();
            System.out.println("package done, start Analysis");
        } else if (aborted.exists()) {
            sapforTasksPackage.state = TasksPackageState.Aborted;
            planner.UpdateSapforPackage();
            System.out.println("package aborted");
        } else {
            System.out.println("package running");
        }
    }
    //--
    public boolean packageNeedsKill() throws Exception {
        return (boolean) planner.ServerCommand(ServerCode.CheckPackageToKill, sapforTasksPackage.id);
    }
    public void killPackage() throws Exception {
        //----
        File interrupt_file = new File(sapforTasksPackage.workspace, Constants.INTERRUPT);
        //----
        FileUtils.writeStringToFile(interrupt_file, new Date().toString());
        File aborted_file = new File(sapforTasksPackage.workspace, Constants.ABORTED);
        do {
            System.out.println("waiting for interrupt...");
            Thread.sleep(1000);
        } while (!aborted_file.exists());
        System.out.println("coup de grace..");
        String kill_command = "killall -SIGKILL " + sapforTasksPackage.sapfor_process_name;
        System.out.println(kill_command);
        Process killer = Runtime.getRuntime().exec(kill_command);
        killer.waitFor();
        System.out.println("done!");
    }
    public void AnalysePackage() throws Exception {
        Vector<String> summary_lines = new Vector<>();
        File results_json_file = new File(sapforTasksPackage.workspace, Constants.results_json);
        if (results_json_file.exists()) {
            SapforTasksResults_json results_json = (SapforTasksResults_json) Utils.jsonFromFile(results_json_file, SapforTasksResults_json.class);
            summary_lines.add("Всего задач: " + results_json.tasks.size());
            LinkedHashMap<TaskState, LinkedHashMap<String, LinkedHashMap<String, Vector<SapforTask>>>> sortedTasks = new LinkedHashMap<>();
            //рассортировать задачи по конфигурациям.
            for (TaskState state : TaskState.values()) {
                LinkedHashMap<String, LinkedHashMap<String, Vector<SapforTask>>> tasksByFlags = new LinkedHashMap<>();
                sortedTasks.put(state, tasksByFlags);
                //--
                for (SapforTask task : results_json.tasks) {
                    task.sapfortaskspackage_id = sapforTasksPackage.id;
                    if (task.state.equals(state)) {
                        LinkedHashMap<String, Vector<SapforTask>> groups_tasks = null;
                        if (tasksByFlags.containsKey(task.flags)) {
                            groups_tasks = tasksByFlags.get(task.flags);
                        } else {
                            groups_tasks = new LinkedHashMap<>();
                            tasksByFlags.put(task.flags, groups_tasks);
                        }
                        Vector<SapforTask> tasks = null;
                        if (groups_tasks.containsKey(task.group_description)) {
                            tasks = groups_tasks.get(task.group_description);
                        } else {
                            tasks = new Vector<>();
                            groups_tasks.put(task.group_description, tasks);
                        }
                        tasks.add(task);
                    }
                }
            }
            //--
            for (TaskState state : sortedTasks.keySet()) {
                LinkedHashMap<String, LinkedHashMap<String, Vector<SapforTask>>> tasksByFlags = sortedTasks.get(state);
                if (!tasksByFlags.isEmpty()) {
                    int count = 0;
                    if (!state.equals(TaskState.Done)) {
                        Vector<String> flagsLines = new Vector<>();
                        for (String flags : tasksByFlags.keySet()) {
                            LinkedHashMap<String, Vector<SapforTask>> tasksByGroups = tasksByFlags.get(flags);
                            for (String group : tasksByGroups.keySet()) {
                                Vector<SapforTask> tasks = tasksByGroups.get(group);
                                flagsLines.add("Группа " + group + ": " + tasks.size());
                                count += tasks.size();
                                for (SapforTask task : tasks) {
                                    task.versionsDescription = task.getVersionsChain();
                                    flagsLines.add(
                                            "тест: " +
                                                    Utils.Brackets(task.test_description) + " " +
                                                    "флаги: "
                                                    + Utils.Brackets(flags) + " " +
                                                    "версии: " +
                                                    task.versionsDescription
                                                  //  + " " +   "конфигурация " + task.sapfor_configuration_id
                                    );
                                }
                            }
                        }
                        summary_lines.add(state.getDescription() + " :" + count);
                        summary_lines.addAll(flagsLines);
                    } else {
                        for (String flags : tasksByFlags.keySet()) {
                            LinkedHashMap<String, Vector<SapforTask>> tasksByGroups = tasksByFlags.get(flags);
                            for (String group : tasksByGroups.keySet()) {
                                Vector<SapforTask> tasks = tasksByGroups.get(group);
                                for (SapforTask task: tasks)
                                    task.versionsDescription = task.getVersionsChain();
                                count += tasks.size();
                            }
                        }
                        summary_lines.add(state.getDescription() + " :" + count);
                    }
                }
            }
            sapforTasksPackage.summary = String.join("\n", summary_lines);
            for (SapforTask task : results_json.tasks) {
                //--
                if (!task.filesList.isEmpty())
                    task.files = String.join("\n", task.filesList);
                //---
                task.filesList = null;
                task.versions = null;
                task.variants = null;
            }
            planner.ServerCommand(ServerCode.PublishSapforPackageTasks, planner.email, new Vector<>(results_json.tasks));
        }
    }
    public void Perform() throws Exception {
        if (packageNeedsKill()) {
            System.out.println("PACKAGE " + sapforTasksPackage.id + " NEEDS TO KILL");
            killPackage();
            sapforTasksPackage.state = TasksPackageState.Aborted;
            planner.UpdateSapforPackage();
        } else {
            switch (sapforTasksPackage.state) {
                case TestsSynchronize:
                    TestsSynchronize();
                    sapforTasksPackage.state = TasksPackageState.RunningPreparation;
                    planner.UpdateSapforPackage();
                    break;
                case RunningPreparation:
                    PackageStart();
                    break;
                case RunningExecution:
                    CheckPackageState();
                    break;
                case Analysis:
                    AnalysePackage();
                    sapforTasksPackage.state = TasksPackageState.Done;
                    planner.UpdateSapforPackage();
                    break;
                default:
                    break;
            }
        }
    }
}
