package com.crowdin.cli.commands.actions;

import com.crowdin.cli.client.CrowdinProjectFull;
import com.crowdin.cli.client.ProjectClient;
import com.crowdin.cli.commands.NewAction;
import com.crowdin.cli.commands.Outputter;
import com.crowdin.cli.commands.functionality.FilesInterface;
import com.crowdin.cli.commands.functionality.ProjectFilesUtils;
import com.crowdin.cli.commands.functionality.SourcesUtils;
import com.crowdin.cli.properties.PropertiesWithFiles;
import com.crowdin.cli.utils.PlaceholderUtil;
import com.crowdin.cli.utils.Utils;
import com.crowdin.cli.utils.concurrency.ConcurrencyUtil;
import com.crowdin.cli.utils.console.ConsoleSpinner;
import com.crowdin.client.sourcefiles.model.Branch;
import com.crowdin.client.sourcefiles.model.FileInfo;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import static com.crowdin.cli.BaseCli.RESOURCE_BUNDLE;
import static com.crowdin.cli.utils.console.ExecutionStatus.OK;
import static com.crowdin.cli.utils.console.ExecutionStatus.WARNING;

public class DownloadSourcesAction implements NewAction<PropertiesWithFiles, ProjectClient> {

    private FilesInterface files;
    private boolean noProgress;
    private boolean plainView;
    private String branchName;
    private boolean debug;

    public DownloadSourcesAction(
        FilesInterface files, boolean noProgress, boolean plainView, String branchName, boolean debug
    ) {
        this.files = files;
        this.noProgress = noProgress;
        this.plainView = plainView;
        this.branchName = branchName;
        this.debug = debug;
    }


    @Override
    public void act(Outputter out, PropertiesWithFiles properties, ProjectClient client) {
        if (!plainView && !properties.getPreserveHierarchy()) {
            out.println(WARNING.withIcon(RESOURCE_BUNDLE.getString("message.download_sources.preserve_hierarchy_warning")));
        }

        CrowdinProjectFull project = ConsoleSpinner
            .execute(out, "message.spinner.fetching_project_info", "error.collect_project_info",
                this.noProgress, this.plainView, client::downloadFullProject);

        Long branchId = Optional.ofNullable(this.branchName)
            .map(br -> project.findBranchByName(br)
                .orElseThrow(() -> new RuntimeException(RESOURCE_BUNDLE.getString("error.not_found_branch"))))
            .map(Branch::getId)
            .orElse(null);
        List<FileInfo> fileInfos = project.getFileInfos().stream()
            .filter(f -> Objects.equals(f.getBranchId(), branchId))
            .collect(Collectors.toList());

        Map<String, FileInfo> filePaths = ProjectFilesUtils.buildFilePaths(project.getDirectories(), fileInfos);

        PlaceholderUtil placeholderUtil =
            new PlaceholderUtil(project.getSupportedLanguages(), project.getProjectLanguages(true), properties.getBasePath());

        AtomicBoolean isAnyFileDownloaded = new AtomicBoolean(false);

        List<Runnable> tasks = properties
            .getFiles()
            .stream()
            .flatMap(fileBean -> SourcesUtils
                .filterProjectFiles(
                    new ArrayList<>(filePaths.keySet()), fileBean.getSource(),
                    fileBean.getIgnore(), properties.getPreserveHierarchy(), placeholderUtil)
                .stream()
                .sorted()
                .map(filePath -> (Runnable) () -> {
                    Long fileId = filePaths.get(filePath).getId();
                    this.downloadFile(client, fileId, Utils.joinPaths(properties.getBasePath(), filePath));
                    isAnyFileDownloaded.set(true);
                    if (!plainView) {
                        out.println(OK.withIcon(String.format(RESOURCE_BUNDLE.getString("message.downloaded_file"), filePath)));
                    } else {
                        out.println(filePath);
                    }
                })
            ).collect(Collectors.toList());
        ConcurrencyUtil.executeAndWait(tasks, debug);

        if (!isAnyFileDownloaded.get()) {
            out.println(WARNING.withIcon(RESOURCE_BUNDLE.getString("error.no_sources")));
        }
    }

    private void downloadFile(ProjectClient client, Long fileId, String filePath) {
        URL url = client.downloadFile(fileId);
        try (InputStream data = url.openStream()) {
            files.writeToFile(filePath, data);
        } catch (IOException e) {
            throw new RuntimeException(String.format(RESOURCE_BUNDLE.getString("error.write_file"), filePath), e);
        }
    }
}
@@ -1047,16 +1047,48 @@
 lectors;
+%0Aimport java.util.stream.Stream;
 %0A%0Aimport
@@ -3312,16 +3312,62 @@
 eBean -%3E
+ %7B%0A                List%3CString%3E foundSources =
  Sources
@@ -3372,16 +3372,20 @@
 esUtils%0A
+    
         
@@ -3429,24 +3429,28 @@
             
+   
+ 
 new ArrayLis
@@ -3496,16 +3496,20 @@
 urce(),%0A
+    
         
@@ -3593,16 +3593,17 @@
 derUtil)
+;
 %0A       
@@ -3615,44 +3615,447 @@
     
-.stream()%0A                .sorted()%0A
+if (foundSources.isEmpty()) %7B%0A                    return Stream.of((Runnable) () -%3E %7B%0A                        if (!plainView) %7B%0A                            out.println(WARNING.withIcon(String.format(RESOURCE_BUNDLE.getString(%22error.no_sources%22), fileBean.getSource())));%0A                        %7D%0A                    %7D);%0A                %7D%0A                return foundSources%0A                    .stream()%0A                    .sorted()%0A    
     
@@ -4118,24 +4118,28 @@
             
+   
+ 
 Long fileId 
@@ -4173,16 +4173,20 @@
 etId();%0A
+    
         
@@ -4305,16 +4305,20 @@
         
+    
 isAnyFil
@@ -4352,32 +4352,36 @@
                 
+ 
+   
 if (!plainView) 
@@ -4374,32 +4374,36 @@
  (!plainView) %7B%0A
+    
                 
@@ -4535,16 +4535,20 @@
         
+    
 %7D else %7B
@@ -4548,16 +4548,20 @@
  else %7B%0A
+    
         
@@ -4611,32 +4611,36 @@
                 
+    
 %7D%0A              
@@ -4641,18 +4641,41 @@
         
+ 
+   %7D);%0A                
 %7D
-)
 %0A       
@@ -4768,151 +4768,8 @@
 ug);
-%0A%0A        if (!isAnyFileDownloaded.get()) %7B%0A            out.println(WARNING.withIcon(RESOURCE_BUNDLE.getString(%22error.no_sources%22)));%0A        %7D
 %0A   

Fix message