package ctbrec.ui.action;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.UUID;
import java.util.function.Consumer;

import javax.imageio.ImageIO;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ctbrec.Config;
import ctbrec.Model;
import ctbrec.StringUtil;
import ctbrec.ui.controls.Dialogs;
import ctbrec.ui.controls.FileSelectionBox;
import javafx.geometry.Insets;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;

public class SetPortraitAction extends AbstractPortraitAction {
    private static final Logger LOG = LoggerFactory.getLogger(SetPortraitAction.class);

    private Consumer<Model> callback;

    public SetPortraitAction(Node source, Model selectedModel, Consumer<Model> callback) {
        this.source = source;
        this.model = selectedModel;
        this.callback = callback;
    }

    public void execute() {
        source.setCursor(Cursor.WAIT);
        String portraitId = Config.getInstance().getSettings().modelPortraits.getOrDefault(model.getUrl(),
                UUID.nameUUIDFromBytes(model.getUrl().getBytes(StandardCharsets.UTF_8)).toString());

        GridPane pane = new GridPane();
        Label l = new Label("Select a portrait image. Leave empty to remove a portrait again.");
        pane.add(l, 0, 0);
        FileSelectionBox portraitSelectionBox = new FileSelectionBox();
        pane.add(portraitSelectionBox, 0, 1);
        GridPane.setMargin(l, new Insets(5));
        GridPane.setMargin(portraitSelectionBox, new Insets(5));
        boolean accepted = Dialogs.showCustomInput(source.getScene(), "Select a portrait image", pane);
        if (!accepted) {
            source.setCursor(Cursor.DEFAULT);
            return;
        }
        String selectedFile = portraitSelectionBox.fileProperty().getValue();

        if (StringUtil.isBlank(selectedFile)) {
            removePortrait(portraitId);
        } else {
            LOG.debug("User selected {}", selectedFile);
            boolean success = processImageFile(portraitId, selectedFile);
            if (success) {
                Config.getInstance().getSettings().modelPortraits.put(model.getUrl(), portraitId);
                try {
                    Config.getInstance().save();
                    firePortraitChanged();
                    runCallback();
                } catch (IOException e) {
                    Dialogs.showError("Set Portrait", "Couldn't change portrait image: ", e);
                }
            }
        }
        source.setCursor(Cursor.DEFAULT);
    }

    private void removePortrait(String portraitId) {
        File portraitFile = getPortraitFile(portraitId);
        try {
            if (portraitFile.exists()) {
                Files.delete(portraitFile.toPath());
            }
            Config.getInstance().getSettings().modelPortraits.remove(model.getUrl());
            Config.getInstance().save();
            runCallback();
        } catch (IOException e) {
            Dialogs.showError("Remove Portrait", "Couldn't remove portrait image: ", e);
        }
    }

    private void runCallback() {
        if (callback != null) {
            try {
                callback.accept(model);
            } catch (Exception e) {
                LOG.error("Error while executing callback", e);
            }
        }
    }

    private boolean processImageFile(String portraitId, String selectedFile) {
        try {
            BufferedImage original = ImageIO.read(new File(selectedFile));
            BufferedImage croppedImage = cropImage(original);
            BufferedImage portrait = convertToScaledJpg(croppedImage);
            boolean success = copyToCacheAsJpg(portraitId, portrait);
            if (!success) {
                LOG.debug("Available formats: {}", Arrays.toString(ImageIO.getWriterFormatNames()));
                throw new IOException("No suitable writer found for image format " + FORMAT);
            }
            return success;
        } catch (IOException e) {
            LOG.error("Error while changing portrait image", e);
            Dialogs.showError("Set Portrait", "Couldn't change portrait image: ", e);
            return false;
        }
    }
}
