package de.hftstuttgart.rest.v1.unittest;

import de.hftstuttgart.utils.JGitUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.core.env.Environment;
import org.springframework.util.FileSystemUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.annotation.MultipartConfig;
import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Rest controller for anything related to the TEST files.
 */
@RestController
@RequestMapping("/v1/unittest")
@MultipartConfig
public class UnitTestUpload {

    private static final Logger LOG = LogManager.getLogger(UnitTestUpload.class);
    public final static String modocotTestConfigRegex = "^modocot::(.*)::(.*|none)::(.*|none)::(.*)$";
    public final static String modocotDueConfigRegex = "^modocot::(.*)::(.*|none)::(.*|none)$";

    private final JGitUtil jGitUtil;
    private final String assignmentBasePath;

    public UnitTestUpload(Environment env, JGitUtil jGitUtil) {
        this.jGitUtil = jGitUtil;

        Path p = Paths.get(env.getProperty("modocot.dir"), env.getProperty("modocot.dir.test.folder.name"));
        this.assignmentBasePath = p.toAbsolutePath().toString();
    }

    /**
     * Create a subfolder for the specific assignment.
     * This is called when the teacher creates an assignment and uploads the JUnit test files
     *
     * @param unitTestFileRef The text file which contains the JUnit tests meta data
     * @param assignmentId    ID of the created assignment. Generated by Moodle
     */
    @RequestMapping(method = RequestMethod.POST)
    public void uploadUnitTestFile(
        @RequestParam("unitTestFile") MultipartFile unitTestFileRef,
        @RequestParam("assignmentId") String assignmentId
    ) throws IOException {
        LOG.info("received new assignment");

        File file = Paths.get(
                this.assignmentBasePath,
                assignmentId + ".txt")
            .toFile();
        file.mkdirs();

        // save assignment config
        unitTestFileRef.transferTo(file);
        LOG.debug(String.format("saved config file to: %s", file.getAbsolutePath()));

        Pattern pattern = Pattern.compile(this.modocotTestConfigRegex);
        Matcher config = null;

        LOG.debug("reading test configuration file");
        // open saved config in a try-with
        try (BufferedReader br = new BufferedReader(
            new InputStreamReader(
                new FileInputStream(file)))) {
            String line;

            // search for a modocot URI while none is found and there are lines left
            while (config == null && (line = br.readLine()) != null) {
                Matcher matcher = pattern.matcher(line);
                if (matcher.matches()) {
                    LOG.debug(String.format("found modocot test line: %s", line));
                    config = matcher;
                }
            }
        } catch (IOException e) {
            LOG.error("Error while reading repo config", e);
        }
        finally {
            if (config == null) {
                throw new RuntimeException("couldn't find repo config for unittest clone");
            }
        }

        LOG.debug("calling test repo clone");
        // cloning assignment repo to persistent space
        jGitUtil.cloneRepository(
            config,
            Paths.get(this.assignmentBasePath, assignmentId).toAbsolutePath().toString());

        LOG.info(String.format("stored new assignment: %s", file.getAbsolutePath()));
    }

    /**
     * Delete the folder for the assignment.
     * Called when the teacher deletes the JUnitTest assignment
     * <p>
     * {{url}}:8080/v1/unittest?assignmentId=111
     *
     * @param assignmentId ID of the assignment to delete. Generated by Moodle
     */
    @RequestMapping(method = RequestMethod.DELETE)
    public void deleteUnitTestFiles(@RequestParam("assignmentId") String assignmentId) {
        LOG.info(String.format("received deletion order for assignment %s", assignmentId));

        // deleting config file
        File file = Paths.get(
            this.assignmentBasePath,
            assignmentId + ".txt")
            .toFile();
        file.delete();

        // deleting local copy of repository
        file = Paths.get(
            this.assignmentBasePath,
            assignmentId).toFile();
        FileSystemUtils.deleteRecursively(file);

        LOG.info(String.format("assignment %s deletion complete", assignmentId));
    }
}
