package games.strategy.engine.framework.map.download;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;

import javax.swing.DefaultListModel;

import games.strategy.debug.ClientLogger;
import games.strategy.ui.SwingComponents;
import games.strategy.util.ThreadUtil;
import games.strategy.util.Version;

class FileSystemAccessStrategy {

  FileSystemAccessStrategy() {}

  Optional<Version> getMapVersion(final String mapName) {
    final File potentialFile = new File(mapName);

    if (!potentialFile.exists()) {
      return Optional.empty();
    } else {
      final DownloadFileProperties props = DownloadFileProperties.loadForZip(potentialFile);
      if (props.getVersion() == null) {
        return Optional.empty();
      } else {
        return Optional.of(props.getVersion());
      }
    }
  }

  static void remove(final List<DownloadFileDescription> toRemove, final DefaultListModel<String> listModel) {
    SwingComponents.promptUser("Remove Maps?",
        "<html>Will remove " + toRemove.size() + " maps, are you sure? <br/>"
            + formatMapList(toRemove, map -> map.getMapName()) + "</html>",
        createRemoveMapAction(toRemove, listModel));
  }

  private static Runnable createRemoveMapAction(final List<DownloadFileDescription> maps,
      final DefaultListModel<String> listModel) {
    return () -> {
      final List<DownloadFileDescription> fails = new ArrayList<>();
      final List<DownloadFileDescription> deletes = new ArrayList<>();

      // delete the map files
      for (final DownloadFileDescription map : maps) {
        try {
          Files.delete(map.getInstallLocation().toPath());
        } catch (final IOException e) {
          ClientLogger.logQuietly(e);
        }
        map.getInstallLocation().delete();
      }

      // now sleep a short while before we check our work
      ThreadUtil.sleep(10);

      // check our work, see if we actuall deleted stuff
      for (final DownloadFileDescription map : maps) {
        if (map.getInstallLocation().exists()) {
          fails.add(map);
        } else {
          deletes.add(map);
        }
      }


      if (!deletes.isEmpty()) {
        showRemoveSuccessDialog("Successfully removed.", deletes);
        // only once we know for sure we deleted things, then delete the ".properties" file
        deletes.forEach(dl -> (new File(dl.getInstallLocation() + ".properties")).delete());
        deletes.forEach(m -> listModel.removeElement(m.getMapName()));
      }

      if (!fails.isEmpty()) {
        showRemoveFailDialog("Unable to delete some of the maps files.<br />"
            + "Manual removal of the files may be necessary:", fails);
        fails.forEach(m -> m.getInstallLocation().deleteOnExit());
      }
    };
  }

  private static void showRemoveFailDialog(final String failMessage, final List<DownloadFileDescription> mapList) {
    final String message = createDialogMessage(failMessage, mapList);
    showDialog(message, mapList, (map) -> map.getInstallLocation().getAbsolutePath());
  }

  private static void showRemoveSuccessDialog(final String successMessage,
      final List<DownloadFileDescription> mapList) {
    final String message = createDialogMessage(successMessage, mapList);
    showDialog(message, mapList, (map) -> map.getMapName());
  }

  private static void showDialog(final String message, final List<DownloadFileDescription> mapList,
      final Function<DownloadFileDescription, String> outputFunction) {
    final StringBuilder sb = new StringBuilder("<html>" + message + "<br /> " + formatMapList(mapList, outputFunction));
    sb.append("</html>");

    SwingComponents.newMessageDialog(sb.toString());
  }

  private static String createDialogMessage(final String message, final List<DownloadFileDescription> mapList) {
    final String plural = mapList.size() > 0 ? "s" : "";
    return message + " " + mapList.size() + " map" + plural;
  }

  private static String formatMapList(final List<DownloadFileDescription> mapList,
      final Function<DownloadFileDescription, String> outputFunction) {
    final int maxMapsToList = 6;
    final StringBuilder sb = new StringBuilder("<ul>");
    for (int i = 0; i < mapList.size(); i++) {
      if (i > maxMapsToList) {
        sb.append("<li>...</li>");
        break;
      } else {
        sb.append("<li>").append(outputFunction.apply(mapList.get(i))).append("</li>");
      }
    }
    return sb.toString();
  }
}
