package ctbrec.ui.settings;

import static javafx.scene.control.ButtonType.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Collections;
import java.util.List;

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

import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.Types;

import ctbrec.Config;
import ctbrec.Model;
import ctbrec.io.ModelJsonAdapter;
import ctbrec.sites.Site;
import ctbrec.ui.AutosizeAlert;
import ctbrec.ui.controls.Dialogs;
import javafx.geometry.Insets;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.stage.FileChooser;

public class IgnoreList extends GridPane {

    private static final Logger LOG = LoggerFactory.getLogger(IgnoreList.class);

    private ListView<Model> ignoreListView;

    private List<Site> sites;

    public IgnoreList(List<Site> sites) {
        this.sites = sites;
        createGui();
        loadIgnoredModels();
    }

    private void createGui() {
        setHgap(10);
        setVgap(10);
        setPadding(new Insets(20, 10, 10, 10));

        Label headline = new Label("Ignore List");
        headline.getStyleClass().add("settings-group-label");
        add(headline, 0, 0);

        ignoreListView = new ListView<>();
        ignoreListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        ignoreListView.addEventHandler(KeyEvent.KEY_PRESSED, event -> {
            if (event.getCode() == KeyCode.DELETE) {
                removeSelectedModels();
            }
        });
        add(ignoreListView, 0, 1);
        GridPane.setHgrow(ignoreListView, Priority.ALWAYS);

        Button remove = new Button("Remove");
        remove.setOnAction(evt -> removeSelectedModels());
        Button exportIgnoreList = new Button("Export");
        exportIgnoreList.setOnAction(e -> exportIgnoreList());
        Button importIgnoreList = new Button("Import");
        importIgnoreList.setOnAction(e -> importIgnoreList());
        HBox buttons = new HBox(10, remove, exportIgnoreList, importIgnoreList);
        add(buttons, 0, 2);
        buttons.setStyle("-fx-background-color: -fx-background"); // workaround so that the buttons don't shrink
    }

    private void removeSelectedModels() {
        List<Model> selectedModels = ignoreListView.getSelectionModel().getSelectedItems();
        if (selectedModels.isEmpty()) {
            return;
        } else {
            Config.getInstance().getSettings().modelsIgnored.removeAll(selectedModels);
            ignoreListView.getItems().removeAll(selectedModels);
            LOG.debug(Config.getInstance().getSettings().modelsIgnored.toString());
            try {
                Config.getInstance().save();
            } catch (IOException e) {
                LOG.warn("Couldn't save config", e);
            }
        }
    }

    private void loadIgnoredModels() {
        List<Model> ignored = Config.getInstance().getSettings().modelsIgnored;
        ignoreListView.getItems().clear();
        ignoreListView.getItems().addAll(ignored);
        Collections.sort(ignoreListView.getItems());
    }

    public void refresh() {
        loadIgnoredModels();
    }

    private void exportIgnoreList() {
        FileChooser chooser = new FileChooser();
        chooser.setTitle("Export ignore list");
        chooser.setInitialFileName("ctbrec-ignorelist.json");
        File file = chooser.showSaveDialog(null);
        if (file != null) {
            Moshi moshi = new Moshi.Builder().add(Model.class, new ModelJsonAdapter(sites)).build();
            Type modelListType = Types.newParameterizedType(List.class, Model.class);
            JsonAdapter<List<Model>> adapter = moshi.adapter(modelListType);
            adapter = adapter.indent("  ");
            try (FileOutputStream out = new FileOutputStream(file)) {
                String json = adapter.toJson(Config.getInstance().getSettings().modelsIgnored);
                out.write(json.getBytes(StandardCharsets.UTF_8));
            } catch (IOException e) {
                Dialogs.showError(getScene(), "Couldn't export ignore list", e.getLocalizedMessage(), e);
            }
        }
    }

    private void importIgnoreList() {
        FileChooser chooser = new FileChooser();
        chooser.setTitle("Import ignore list");
        File file = chooser.showOpenDialog(null);
        if (file != null) {
            Moshi moshi = new Moshi.Builder().add(Model.class, new ModelJsonAdapter(sites)).build();
            Type modelListType = Types.newParameterizedType(List.class, Model.class);
            JsonAdapter<List<Model>> adapter = moshi.adapter(modelListType);
            try {
                byte[] fileContent = Files.readAllBytes(file.toPath());
                List<Model> ignoredModels = adapter.fromJson(new String(fileContent, StandardCharsets.UTF_8));
                boolean confirmed = true;
                if (!Config.getInstance().getSettings().modelsIgnored.isEmpty()) {
                    String msg = "This will replace the existing ignore list! Continue?";
                    AutosizeAlert confirm = new AutosizeAlert(AlertType.CONFIRMATION, msg, getScene(), YES, NO);
                    confirm.setTitle("Import ignore list");
                    confirm.setHeaderText("Overwrite ignore list");
                    confirm.showAndWait();
                    confirmed = confirm.getResult() == ButtonType.YES;
                }
                if (confirmed) {
                    Config.getInstance().getSettings().modelsIgnored = ignoredModels;
                    refresh();
                }
            } catch (IOException e) {
                Dialogs.showError(getScene(), "Couldn't import ignore list", e.getLocalizedMessage(), e);
            }
        }
    }
}
