package io.github.atomfrede.gradle.plugins.crowdincli.task.download;

import io.github.atomfrede.gradle.plugins.crowdincli.CrowdinCliPlugin;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.Task;
import org.gradle.api.file.RelativePath;
import org.gradle.api.internal.file.FileResolver;
import org.gradle.api.internal.file.copy.CopyAction;
import org.gradle.api.internal.file.copy.CopySpecInternal;
import org.gradle.api.internal.file.copy.DestinationRootCopySpec;
import org.gradle.api.internal.file.copy.FileCopyAction;
import org.gradle.api.tasks.AbstractCopyTask;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.internal.reflect.Instantiator;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
 * This tasks depends on @{@link CrowdinCliDownloadTask} and extracts the downloaded
 * crowdin-cli.zip to 'gradle/corowdin-cli/crowdin-cli.jar`. The content of the
 * archive is flatted such that only the executable jar file is extracted to the destination directory.
 */
public class CrowdinCliUnzipTask extends AbstractCopyTask {

    public static final String TASK_NAME = "unzipCrowdinCli";
    public static final String DESCRIPTION = "Unzip the crowdin cli into gradle/crowdin-cli";

    public CrowdinCliUnzipTask() {

        super();
        getProject().getTasksByName("unzipCrowdinCli", true);
        setDependsOn(Collections.singletonList(getDownloadTask()));
        setGroup(CrowdinCliPlugin.GROUP);
        setDescription(DESCRIPTION);

        // only include the crowdin-cli.jar
        include("**/*.jar");
        setIncludeEmptyDirs(false);

        from(getProject().zipTree(getDownloadTask().getDest()));

        setDestinationDir(getDownloadTask().getDest().getParentFile());

        // flatten the result, such that we have a stable path where to find the crowdin cli executable
        eachFile(fileCopyDetails -> fileCopyDetails.setRelativePath(new RelativePath(true, fileCopyDetails.getName())));

    }

    private CrowdinCliDownloadTask getDownloadTask() {

        Set<Task> tasks = getProject().getTasksByName(CrowdinCliDownloadTask.TASK_NAME, true);

        List<Task> allTasks = new ArrayList<>();
        allTasks.addAll(tasks);

        if (allTasks.size() == 0) {
            getLogger().error("Required task {} is missing.", CrowdinCliDownloadTask.TASK_NAME);
            throw new RuntimeException(String.format("Required task %s is missing.", CrowdinCliDownloadTask.TASK_NAME));
        }

        return (CrowdinCliDownloadTask) allTasks.get(0);
    }

    @Override
    protected CopyAction createCopyAction() {
        File destinationDir = this.getDestinationDir();
        if (destinationDir == null) {
            throw new InvalidUserDataException("No copy destination directory has been specified, use 'into' to specify a target directory.");
        } else {
            return new FileCopyAction(this.getFileLookup().getFileResolver(destinationDir));
        }
    }

    @Override
    protected CopySpecInternal createRootSpec() {

        Instantiator instantiator = this.getInstantiator();
        FileResolver fileResolver = this.getFileResolver();
        return (CopySpecInternal)instantiator.newInstance(DestinationRootCopySpec.class, new Object[]{fileResolver, super.createRootSpec()});
    }

    public DestinationRootCopySpec getRootSpec() {
        return (DestinationRootCopySpec)super.getRootSpec();
    }

    @OutputDirectory
    public File getDestinationDir() {
        return this.getRootSpec().getDestinationDir();
    }

    public void setDestinationDir(File destinationDir) {
        this.into(destinationDir);
    }
}

@@ -578,24 +578,58 @@
 ctCopyTask;%0A
+import org.gradle.api.tasks.Copy;%0A
 import org.g
@@ -661,16 +661,16 @@
 ectory;%0A
-
 import o
@@ -1154,32 +1154,20 @@
 extends 
-AbstractCopyTask
+Copy
  %7B%0A%0A    
@@ -2559,24 +2559,24 @@
 %0A        %7D%0A%0A
+
         retu
@@ -2629,1104 +2629,7 @@
    %7D
-%0A%0A    @Override%0A    protected CopyAction createCopyAction() %7B%0A        File destinationDir = this.getDestinationDir();%0A        if (destinationDir == null) %7B%0A            throw new InvalidUserDataException(%22No copy destination directory has been specified, use 'into' to specify a target directory.%22);%0A        %7D else %7B%0A            return new FileCopyAction(this.getFileLookup().getFileResolver(destinationDir));%0A        %7D%0A    %7D%0A%0A    @Override%0A    protected CopySpecInternal createRootSpec() %7B%0A%0A        Instantiator instantiator = this.getInstantiator();%0A        FileResolver fileResolver = this.getFileResolver();%0A        return (CopySpecInternal)instantiator.newInstance(DestinationRootCopySpec.class, new Object%5B%5D%7BfileResolver, super.createRootSpec()%7D);%0A    %7D%0A%0A    public DestinationRootCopySpec getRootSpec() %7B%0A        return (DestinationRootCopySpec)super.getRootSpec();%0A    %7D%0A%0A    @OutputDirectory%0A    public File getDestinationDir() %7B%0A        return this.getRootSpec().getDestinationDir();%0A    %7D%0A%0A    public void setDestinationDir(File destinationDir) %7B%0A        this.into(destinationDir);%0A    %7D
 %0A%7D%0A

extend copy instead of abstract copy action