package de.hftstuttgart.rest.v1.unittest;

import de.hftstuttgart.config.ModocotProperties;
import de.hftstuttgart.utils.BackendUtil;
import de.hftstuttgart.utils.FileUtil;
import de.hftstuttgart.utils.GitTeaUtil;
import de.hftstuttgart.utils.JGitUtil;
import de.hftstuttgart.utils.UnzipUtil;
import io.gitea.model.Repository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.jgit.transport.PushResult;
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.File;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 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);

    private final ModocotProperties modocotProperties;
    private final GitTeaUtil gitTeaUtil;
    private final JGitUtil jGitUtil;
    private final String assignmentBasePath;

    public UnitTestUpload(ModocotProperties modocotProperties,
                          GitTeaUtil gitTeaUtil,
                          JGitUtil jGitUtil) {
        this.modocotProperties = modocotProperties;
        this.gitTeaUtil = gitTeaUtil;
        this.jGitUtil = jGitUtil;
        this.assignmentBasePath =
                modocotProperties.getModocotParentDirectory()
                + File.separator
                + modocotProperties.getModocotAssignmentFolderPrefix();
    }

    /**
     * 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 zip file which contains the JUnit tests
     * @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 {

        // path to the directory in which we will be working
        String subFolderPath = this.assignmentBasePath + assignmentId;

        LOG.info("work-directory: " + subFolderPath);
        // creating the work-directory
        File workDirectory = new File(subFolderPath);
        workDirectory.mkdirs();

        // creating the file which the unitTestFileRef will be transferred into
        File file = new File(subFolderPath, String.valueOf(UUID.randomUUID()));

        // transferring MultipartFile into temporary file
        unitTestFileRef.transferTo(file);

        // unzipping temporary file to work-directory
        List<File> zipFiles = UnzipUtil.unzip(file);

        // unzipping temporary file (not needed anymore)
        if (file.exists()) file.delete();

        // check if any extracted files are named repo.txt
        if (zipFiles.stream().anyMatch(zipFile -> zipFile.getName().equalsIgnoreCase("repo.txt"))) {
            // reading all from the  repo.txt
            List<String> lines = BackendUtil.extractLinesFromRepoFile(zipFiles, "repo.txt");
            // either set the first line of repo.txt or ""
            String repoUrl = (lines.size() > 0 && !lines.get(0).equals("")) ?
                    lines.get(0) : "";
            LOG.info("repoUrl: " + repoUrl);
            // either set the second line of repo.txt or null
            String credentials = ((lines.size() > 1) && !lines.get(1).equals("")) ?
                    lines.get(1) : null;
            LOG.info("credentials: " + credentials);
            // cloning repository repoUrl into work-directory, using credentials from second line in repo.txt
            this.jGitUtil.cloneRepository(repoUrl, workDirectory, credentials, credentials != null,true);
        }

        Stream.of(Objects.requireNonNull(workDirectory.listFiles()))
                .forEach(fi -> System.out.println(fi.getAbsolutePath()));

        if(this.gitTeaUtil.repositoryExists(assignmentId)) {
            this.gitTeaUtil.deleteRepository(assignmentId);
        }
        // creating repository on internal giTea, name = assignmentId
        Repository repo = this.gitTeaUtil.createRepository(assignmentId);
        System.out.println(repo);
        // giTea runs in docker and returns CloneUrl as localhost, replacing localhost with docker-host ip
        repo.setCloneUrl(repo.getCloneUrl().replace("localhost", modocotProperties.getDockerHostIp()));

        // committing everything in work-directory and push to created repository
        Iterable<PushResult> pushResults = this.jGitUtil.commitAllAndPush(workDirectory, repo, false);
        if (pushResults != null) {
            for (PushResult pushResult : pushResults) {
                LOG.info("Push-Result: " + pushResult.getMessages());
            }
        }
        // deleting created work-directory
        FileUtil.deleteFolderRecursively(workDirectory);

        LOG.info("Uploaded unit test file: " + workDirectory);
    }

    /**
     * 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) {
        String path = this.assignmentBasePath + assignmentId;
        File dir = new File(path);
        if (dir.exists()) {
            FileUtil.deleteFolderRecursively(dir);
        }
    }
}
