package com.zbw.gitpic.controller;

import com.jfoenix.controls.*;
import com.zbw.gitpic.exception.AuthorizedException;
import com.zbw.gitpic.exception.TipException;
import com.zbw.gitpic.utils.*;
import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.input.*;
import javafx.scene.layout.StackPane;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import org.eclipse.jgit.lib.Repository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.datatransfer.Transferable;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ResourceBundle;

/**
 * @author zbw
 * @create 2018/2/26 16:36
 */
public class MainController extends StackPane implements Initializable {

    private static Logger logger = LoggerFactory.getLogger(MainController.class);

    private Stage stage;

    private String uploadImgFilePath;

    private boolean isGitInit = false;

    private Repository repository = null;

    @FXML
    private StackPane root;

    @FXML
    private JFXTextField projectPathTextField;

    @FXML
    private JFXTextField imgPathTextField;

    @FXML
    private JFXTextField rawUrlTextField;

    @FXML
    private JFXButton commitButton;

    @FXML
    private JFXSpinner promptSpinner;

    @FXML
    private Label promptLabel;

    @FXML
    private JFXSpinner gitSpinner;

    @FXML
    private Label gitLabel;

    @FXML
    private JFXDialog dialog;

    @FXML
    private JFXTextField usernameTextField;

    @FXML
    private JFXPasswordField passwordTextField;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        root.getChildren().remove(dialog); // 先从根组件移除弹窗,否则无法手动初始化弹窗
        stage = new Stage();
        promptSpinner.setVisible(false);
        gitSpinner.setVisible(false);
        dialog.setTransitionType(JFXDialog.DialogTransition.CENTER);
        String projectPath = Preference.getInstance().getProjectPath();
        if (CastUtil.isNotEmpty(projectPath)) {
            projectPathTextField.setText(projectPath);
            initGit(projectPath);
        }

        imgPathTextField.setText(Preference.getInstance().getPicPath());
    }

    /**
     * 主面板onDragOver事件
     *
     * @param event
     */
    @FXML
    protected void setTransferMode(DragEvent event) {
        event.acceptTransferModes(TransferMode.ANY);
    }

    /**
     * 主面板onDragDropped事件
     *
     * @param event
     */
    @FXML
    protected void setUploadImgPath(DragEvent event) {
        Dragboard dragboard = event.getDragboard();
        if (dragboard.hasFiles()) {
            File file = dragboard.getFiles().get(0);
            if (file != null) {
                uploadImgFilePath = file.getAbsolutePath();
            }
        }
        copyAndGenerate();
    }

    /**
     * 选择项目根目录
     */
    @FXML
    protected void chooseProjectPath() {
        DirectoryChooser directoryChooser = new DirectoryChooser();
        directoryChooser.setTitle("选择项目目录");
        File file = directoryChooser.showDialog(stage);
        if (file == null || !file.isDirectory()) {
            return;
        }
        projectPathTextField.setText(file.getAbsolutePath());
        if (CastUtil.isEmpty(projectPathTextField.getText())) {
            return;
        }
        String projectPath = projectPathTextField.getText();
        Preference.getInstance().saveProjectPath(projectPath);
        initGit(projectPath);
    }


    /**
     * 选择图片保存目录
     */
    @FXML
    protected void chooseImgPath() {
        DirectoryChooser directoryChooser = new DirectoryChooser();
        String projectPath = projectPathTextField.getText();
        if (CastUtil.isNotEmpty(projectPath)) {
            File file = new File(projectPath);
            directoryChooser.setInitialDirectory(file);
        }
        directoryChooser.setTitle("选择图片保存目录");
        File file = directoryChooser.showDialog(stage);
        if (file == null || !file.isDirectory()) {
            return;
        }
        imgPathTextField.setText(file.getAbsolutePath());
        Preference.getInstance().savePicPath(imgPathTextField.getText());
    }

    /**
     * 选择要上传的图片
     */
    @FXML
    protected void chooseUploadImg() {
        FileChooser fileChooser = new FileChooser();
        File file = fileChooser.showOpenDialog(stage);
        if (null == file) {
            return;
        }
        uploadImgFilePath = file.getAbsolutePath();
        copyAndGenerate();
    }

    /**
     * 从剪贴板复制
     */
    @FXML
    protected void copyByClipboard() {
        Clipboard clipboard = Clipboard.getSystemClipboard();
        if (clipboard.hasImage()) {
            Image image = clipboard.getImage();
            BufferedImage bImage = SwingFXUtils.fromFXImage(image, null);
            try {
                Path tempDirectory = Files.createTempDirectory(Constants.GITPIC_PREFIX);
                String tempFile = tempDirectory.toString() + File.separator + Constants.GITPIC_PREFIX + System.currentTimeMillis() + ".png";
                File file = new File(tempFile);
                ImageIO.write(bImage, "png", file);
                uploadImgFilePath = file.getAbsolutePath();
                copyAndGenerate();
                file.delete();// 删除临时图片
                Files.delete(tempDirectory);//删除临时目录
            } catch (IOException e) {
                logger.error(e.getMessage(), e);
                showErrorMessage("从剪切板拷贝图片异常", e);
            }
        } else {
            showErrorMessage("剪切板中没有图片");
        }
    }

    /**
     * commit push 按钮
     */
    @FXML
    protected void commitAndPush() {
        commitButton.setDisable(true);
        ThreadPool.getInstance().execute(() -> {
            try {
                showNormalMessage("commit中...");
                GitUtils.commitAll(repository);
                showSuccessMessage("commit成功!");
                pushGit();
            } catch (TipException e) {
                showErrorMessage(e);
                commitButton.setDisable(false);
            }
        });

    }

    /**
     * Dialog面板Accept
     */
    @FXML
    protected void dialogAccept() {
        if (!usernameTextField.validate() || !passwordTextField.validate()) {
            return;
        }
        String username = this.usernameTextField.getText();
        String password = this.passwordTextField.getText();
        Preference.getInstance().saveGitUsername(username);
        Preference.getInstance().saveGitPassword(password);
        pushGit();
        dialog.close();
    }

    /**
     * Dialog面板Cancel
     */
    @FXML
    protected void dialogCancel() {
        dialog.close();
        commitButton.setDisable(false);
        showErrorMessage("push到github失败");
    }

    /**
     * 加载Git项目
     *
     * @param projectPath
     */
    private void initGit(String projectPath) {
        ThreadPool.getInstance().execute(() -> {
            try {
                Platform.runLater(() -> {
                    gitSpinner.setVisible(true);
                    gitLabel.setText("初始化git项目中...");
                });
                repository = GitUtils.init(projectPath);
                isGitInit = true;
                Platform.runLater(() -> {
                    gitSpinner.setVisible(false);
                    gitLabel.setText("项目已加载");
                    gitLabel.getStyleClass().add("text-success");
                });

                showPromptSpinner();
                showNormalMessage("从Github中pull项目...");
                GitUtils.pull(repository);
                hidePromptSpinner();
                showNormalMessage("Pull项目成功");
                commitButton.setDisable(false);
            } catch (TipException e) {
                showErrorMessage(e);
                Platform.runLater(() -> {
                    gitSpinner.setVisible(false);
                    gitLabel.setText("");
                });
            }
        });
    }

    /**
     * 复制文件到git项目下并生成raw链接
     */
    private void copyAndGenerate() {
        if (!isGitInit) {
            showErrorMessage("请先初始化git");
            return;
        }
        try {
            copyToProject();
        } catch (TipException e) {
            showErrorMessage(e);
            return;
        }
        try {
            generateGitRawPath();
        } catch (TipException e) {
            showErrorMessage(e);
        }
    }

    /**
     * 复制图片到git项目下
     */
    private void copyToProject() {
        if (CastUtil.isEmpty(imgPathTextField.getText())) {
            throw new TipException("请先设置保存图片文件夹");
        }
        File file = new File(imgPathTextField.getText());
        if (!file.isDirectory() || !file.exists()) {
            throw new TipException("保存图片文件夹路径不存在");
        }
        File pic = new File(uploadImgFilePath);
        if (!pic.exists() || !pic.isFile()) {
            throw new TipException("保存图片文件夹路径不存在");
        }
        String gitImgPath = imgPathTextField.getText() + File.separator + pic.getName();
        File gitPic = new File(gitImgPath);
        try {
            Files.copy(pic.toPath(), gitPic.toPath());
        } catch (FileAlreadyExistsException e) {
            throw new TipException("项目中有相同文件名文件");
        } catch (IOException e) {
            e.printStackTrace();
            throw new TipException("复制文件失败");
        }
    }

    /**
     * 生成raw链接
     */
    private void generateGitRawPath() {
        File pic = new File(uploadImgFilePath);
        if (!pic.exists() || pic.isDirectory()) {
            throw new TipException("请选择正确的图片文件");
        }
        if (null == repository) {
            throw new TipException("请先初始化git项目");
        }
        String uri = GitUtils.getRemoteUri(repository);
        String branch = GitUtils.getBranch(repository);
        String folder = imgPathTextField.getText().replace(projectPathTextField.getText(), "");
        String name = uploadImgFilePath.substring(uploadImgFilePath.lastIndexOf(File.separator) + 1);
        String url = GitUtils.createGitBlobUrl(uri, branch, folder, name);
        rawUrlTextField.setText(GitUtils.createGitCdnUrl(url));
        rawUrlTextField.requestFocus();
        rawUrlTextField.selectAll();
        rawUrlTextField.copy();
        showSuccessMessage("已复制图片路径到剪切板");
    }

    /**
     * push到git
     */
    private void pushGit() {
        ThreadPool.getInstance().execute(() -> {
            showPromptSpinner();
            showNormalMessage("push到github中...");
            try {
                String uri = GitUtils.getRemoteUri(repository);
                if (Constants.GIT_SSH.equals(GitUtils.authType(uri))) {
                    GitUtils.push(repository);
                    showSuccessMessage("push成功!");
                    hidePromptSpinner();
                    commitButton.setDisable(false);
                } else {
                    String username = Preference.getInstance().getGitUsername();
                    String password = Preference.getInstance().getGitPassword();
                    if (CastUtil.isNotEmpty(username) && CastUtil.isNotEmpty(password)) {
                        try {
                            GitUtils.push(repository, username, password);
                            showSuccessMessage("push成功!");
                            hidePromptSpinner();
                        } catch (AuthorizedException e) {
                            showErrorMessage(e);
                            hidePromptSpinner();
                            Platform.runLater(() -> dialog.show(root));
                        }
                        commitButton.setDisable(false);
                    } else {
                        Platform.runLater(() -> dialog.show(root));
                    }
                }
            } catch (TipException e) {
                commitButton.setDisable(false);
                hidePromptSpinner();
                showErrorMessage(e);
            }
        });
    }

    /**
     * 显示成功信息
     *
     * @param msg
     */
    private void showSuccessMessage(String msg) {
        this.setGitMessageLabel(msg, "text-success");
    }

    /**
     * 显示错误信息
     *
     * @param msg
     */
    private void showErrorMessage(String msg) {
        this.setGitMessageLabel(msg, "text-error");
    }

    /**
     * 显示异常的信息
     *
     * @param e
     */
    private void showErrorMessage(Exception e) {
        this.setGitMessageLabel(e.getMessage(), "text-dark");
    }

    /**
     * 显示带异常信息的错误信息
     *
     * @param msg
     * @param e
     */
    private void showErrorMessage(String msg, Exception e) {
        this.setGitMessageLabel(msg + e.getMessage(), "text-error");
    }

    /**
     * 显示提示信息
     *
     * @param msg
     */
    private void showNormalMessage(String msg) {
        this.setGitMessageLabel(msg, "text-dark");
    }

    /**
     * 显示信息
     *
     * @param msg
     * @param styleClass
     */
    private void setGitMessageLabel(String msg, String... styleClass) {
        Platform.runLater(() -> {
            promptLabel.getStyleClass().clear();
            promptLabel.getStyleClass().addAll(styleClass);
            promptLabel.setText(msg);
        });
    }

    private void showPromptSpinner() {
        Platform.runLater(() -> promptSpinner.setVisible(true));
    }

    private void hidePromptSpinner() {
        Platform.runLater(() -> promptSpinner.setVisible(false));
    }
}