import { setTestCases, getTestCases } from "../visualUI/functions";
import { generate } from "../visualUI/code_generator";
import { IVProgAssessment } from "../assessment/ivprogAssessment";
import { TestConsole } from "./testConsole";
import { parseLogs } from "./../services/userLog";
import { SemanticAnalyser } from "../processor/semantic/semanticAnalyser";
import { Maybe } from "./maybe";
import { parserCodeVisual } from "./codeParser";

function parseActivityData (data, ignore_logs=false) {
  let algorithm_in_ilm = null;
  if (data.split("\n::algorithm::")[1]) {
    algorithm_in_ilm = data.split("\n::algorithm::")[1].split("\n::logs::")[0];
    const logs = data.split("\n::algorithm::")[1].split("\n::logs::")[1];
    if (logs != null && ignore_logs == false) {
      try {
        parseLogs(logs);
      }
      catch (e) {}
    }
  }
  let content;
  try {
    content = JSON.parse(data.split("\n::algorithm::")[0]);
    content["algorithm_in_ilm"] = algorithm_in_ilm;
  } catch (e) {
    console.error(e);
    return Maybe.none();
  }
  return Maybe.some(content);
}

function configAuxiliar (obj_config) {

  return new Map(
      Object
        .keys(obj_config)
        .map(
            key => [key, obj_config[key]]
        )
    )
}
    
function setActivityConfig (config_json) {

  ivprogCore.Config.activity_commands = configAuxiliar(config_json.commands);
  ivprogCore.Config.activity_functions = configAuxiliar(config_json.functions);
  ivprogCore.Config.activity_datatypes = configAuxiliar(config_json.datatypes);
  ivprogCore.Config.activity_filter = configAuxiliar(config_json.filter);
  ivprogCore.Config.activity_programming_type = configAuxiliar(config_json.programming);

}

export function setPreviousAlgorithm (code) {
  
  var code_obj = null;
  try {
    code_obj = ivprogCore.parseCode(code)
    parserCodeVisual(code_obj)
  }
  catch(e) {
    showInvalidData()
    console.log(e)
    return
  }
}

export function prepareActivityToStudentHelperJSON (ilm_cont) {
  
  setTestCases(ilm_cont.test_cases)

  setActivityConfig(ilm_cont.settings)

  if (ilm_cont.code)
    setPreviousAlgorithm(ilm_cont.code)
  else 
    if (ilm_cont.algorithm)
      setPreviousAlgorithm(ilm_cont.algorithm)

}

export function prepareActivityToStudentHelper (ilm_cont, ignore_logs=false) {
  const maybe_content = parseActivityData(ilm_cont, ignore_logs);
  return maybe_content.map((content) => {
    const testCases = content.testcases;
    setTestCases(testCases);

    let prog_type = null;
    if (content.settings_programming_type) {
      prog_type = content.settings_programming_type[0].value;
    } else {
      prog_type = "visual";
    }

    return {
      settingsProgrammingType: prog_type,
      settingsDataTypes: content.settings_data_types,
      settingsCommands: content.settings_commands,
      settingsFunctions: content.settings_functions,
      algorithmInIlm: content.algorithm_in_ilm,
      settingsFilter: content.settings_filter,
    };
  });
}

function compareArray (a, b) {
  for (let i = 0; i < a.length; ++i) {
    const elementA = a[i];
    const elementB = b[i];
    if (elementA != elementB) {
      return false;
    }
  }
  return true;
}

function compareTestcases (original, student) {
  if (original.length != student.length) {
    return false;
  }
  for (let i = 0; i < original.length; ++i) {
    const elementO = original[i];
    const elementS = student[i];
    if (!compareArray(elementO.input, elementS.input)) {
      return false;
    }
    if (!compareArray(elementO.output, elementS.output)) {
      return false;
    }
  }
  return true;
}

export function autoEval (originalData, callback) {
  const code = generate();
  //console.debug(code);
  const original = parseActivityData(originalData).getOrElse(undefined);
  if (original == null) {
    alert("iAssign did not provide the original activity data!");
    return callback(null);
  }
  if (code == null) {
    return callback(-1); // @FeedbackConvention Casos de teste vazios
  } else {
    if (!compareTestcases(original.testcases, getTestCases())) {
      return callback(-2); // @FeedbackConvention Casos de teste alterados pelo aluno
    }
    try {
      const ast_code = SemanticAnalyser.analyseFromSource(code);
      const con = new TestConsole([]);
      const autoAssessment = new IVProgAssessment(
        ast_code,
        original.testcases,
        con
      );
      autoAssessment
        .runTest()
        .then((grade) => callback(grade))
        .catch((err) => {
          console.log(err);
          callback(-5); // @FeedbackConvention Falha na execução
        });
    } catch (e) {
      console.error(e);
      callback(-5);
    }
  }
}