package rb;

import com.intellij.ide.BrowserUtil;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.progress.PerformInBackgroundOption;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.util.PopupUtil;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.changes.*;
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;

import java.net.URI;

/**
 * Created by IntelliJ IDEA.
 * User: Gong Zeng
 * Date: 5/13/11
 * Time: 4:17 PM
 */
public class PostReviewAction extends AnAction {
    String changeMessage = "";

    @Override
    public void actionPerformed(AnActionEvent event) {
        final Project project = event.getData(PlatformDataKeys.PROJECT);
        final VirtualFile[] vFiles = event.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
        if (vFiles == null || vFiles.length == 0) {
            Messages.showMessageDialog("No file to be review", "Alert", null);
            return;
        }
        final AbstractVcs vcs = ProjectLevelVcsManager.getInstance(project).getVcsFor(vFiles[0]);
        if (!ProjectLevelVcsManager.getInstance(project).checkAllFilesAreUnder(vcs, vFiles)) {
            setActionEnable(event, true);
            Messages.showWarningDialog("Some of selected files are not under control of SVN.", "Warning");
            return;
        }

        final ChangeListManager changeListManager = ChangeListManager.getInstance(project);

        for (VirtualFile vf : vFiles) {
            LocalChangeList changeList = changeListManager.getChangeList(vf);
            if (changeList != null) {
                changeMessage = changeList.getName();
                break;
            }
        }

        changeListManager.invokeAfterUpdate(new Runnable() {
            @Override
            public void run() {
                System.out.println("Executing...");
                try {
                    VCSBuilder builder = VCSBuilder.Factory.getBuilder(vcs);
                    if (builder != null) {
                        execute(project, builder, vFiles);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, InvokeAfterUpdateMode.SYNCHRONOUS_CANCELLABLE, "Refresh VCS", ModalityState.current());
    }

    @Override
    public void update(AnActionEvent event) {
        final Project project = event.getData(PlatformDataKeys.PROJECT);

        final VirtualFile[] vFiles = event.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
        if (vFiles == null || vFiles.length == 0) {
            setActionEnable(event, false);
            return;
        }
        final ChangeListManager changeListManager = ChangeListManager.getInstance(project);

        int enableCount = 0;
        for (VirtualFile vf : vFiles) {

            if (vf != null) {
                vf.refresh(false, true);
                Change change = changeListManager.getChange(vf);
                if (change != null) {
                    if (change.getType().equals(Change.Type.NEW)) {
                        enableCount++;
                        continue;
                    }
                    ContentRevision beforeRevision = change.getBeforeRevision();
                    if (beforeRevision != null) {
                        VcsRevisionNumber revisionNumber = beforeRevision.getRevisionNumber();
                        if (!revisionNumber.equals(VcsRevisionNumber.NULL)) {
                            enableCount++;
                        }
                    }
                }
            }
        }
        setActionEnable(event, enableCount == vFiles.length);
    }

    private void setActionEnable(AnActionEvent event, boolean isEnable) {
        event.getPresentation().setEnabled(isEnable);
    }

    private void execute(final Project project, final VCSBuilder vcsBuilder, VirtualFile[] vFiles) throws Exception {
        vcsBuilder.build(project, vFiles);
        final String diff = vcsBuilder.getDiff();
        if (diff == null) {
            Messages.showMessageDialog(project, "No diff generated", "Warn", null);
            return;
        }

        final ReviewBoardClient reviewBoardClient = new ReviewBoardClient();
        Task.Backgroundable task = new Task.Backgroundable(project, "Query Repository...", false, new PerformInBackgroundOption() {
            @Override
            public boolean shouldStartInBackground() {
                return false;
            }

            @Override
            public void processSentToBackground() {
            }
        }) {

            @Override
            public void run(@NotNull ProgressIndicator progressIndicator) {
                progressIndicator.setIndeterminate(true);
                Repository[] repositories;
                try {
                    repositories = reviewBoardClient.getRepositories().repositories;
                } catch (Exception e) {
                    PopupUtil.showBalloonForActiveFrame("Error to list repository:" + e.getMessage(), MessageType.ERROR);
                    throw new RuntimeException(e);
                }
                if (repositories != null) {
                    final Repository[] finalRepositories = repositories;
                    ApplicationManager.getApplication().invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            showPostForm(project, vcsBuilder, finalRepositories);
                        }
                    });

                }
            }
        };
        ProgressManager.getInstance().run(task);
    }

    private void showPostForm(final Project project, final VCSBuilder vcsBuilder, Repository[] repositories) {
        int possibleRepoIndex = getPossibleRepoIndex(vcsBuilder.getRepositoryURL(), repositories);
        final PrePostReviewForm prePostReviewForm = new PrePostReviewForm(project, changeMessage, vcsBuilder.getDiff(), repositories, possibleRepoIndex) {

            @Override
            protected void doOKAction() {
                if (!isOKActionEnabled()) {
                    return;
                }
                final ReviewSettings setting = this.getSetting();
                if (setting == null) {
                    return;
                }
                if (vcsBuilder.getBasePath() == null) {
                    setting.setSvnBasePath("");
                } else {
                    setting.setSvnBasePath(vcsBuilder.getBasePath());
                }
                setting.setSvnRoot(vcsBuilder.getRepositoryURL());
                if (this.getDiff() != null) {
                    setting.setDiff(this.getDiff());
                } else {
                    setting.setDiff(vcsBuilder.getDiff());
                }
                Task.Backgroundable task = new Task.Backgroundable(project, "Running", false, new PerformInBackgroundOption() {
                    @Override
                    public boolean shouldStartInBackground() {
                        return false;
                    }

                    @Override
                    public void processSentToBackground() {
                    }
                }) {
                    boolean result;

                    @Override
                    public void onSuccess() {
                        if (result) {
                            String url = ReviewBoardSettings.getSettings().getServer() + "/r/" + setting.getReviewId() + "/diff/";
                            int success = Messages.showYesNoDialog("The review url is " + url + "\r\n" +
                                    "Open the url?", "Success", null);
                            if (success == 0) {
                                BrowserUtil.browse(url);
                            }
                        } else {
//                            Messages.showErrorDialog("Post review failure", "Error");
                            PopupUtil.showBalloonForActiveFrame("Post review failure", MessageType.ERROR);
                        }
                    }

                    @Override
                    public void run(@NotNull ProgressIndicator progressIndicator) {
                        progressIndicator.setIndeterminate(true);
                        try {
                            result = ReviewBoardClient.postReview(setting, progressIndicator);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                };
                ProgressManager.getInstance().run(task);
                super.doOKAction();
            }
        };
        prePostReviewForm.show();
    }

    private int getPossibleRepoIndex(@NotNull String repositoryUrl, Repository[] repositories) {
        int possibleRepoIndex = -1;
        for (int j = 0; j < repositories.length; j++) {
            if (repositoryUrl.equals(repositories[j].mirror_path)) {
                possibleRepoIndex = j;
                break;
            }
        }
        if (possibleRepoIndex == -1) {
            int i = repositoryUrl.lastIndexOf('/');
            if (i > -1) {
                String shortName = repositoryUrl.substring(i + 1);
                for (int j = 0; j < repositories.length; j++) {
                    if (shortName.equals(repositories[j].name)) {
                        possibleRepoIndex = j;
                        break;
                    }
                }
            }
        }
        if (possibleRepoIndex == -1) {
            if (!repositoryUrl.contains("//")) {
                repositoryUrl = "//" + repositoryUrl;
            }
            String path = URI.create(repositoryUrl).getPath();
            String[] repos = new String[repositories.length];
            for (int i = 0; i < repos.length; i++) {
                repos[i] = repositories[i].name;
            }
            possibleRepoIndex = LevenshteinDistance.getClosest(path, repos);
        }

        return possibleRepoIndex;
    }


    public boolean isDumbAware() {
        return true;
    }
}