package floobits;

import com.intellij.ide.impl.ProjectUtil;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManager;
import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.fileChooser.impl.FileChooserUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.platform.PlatformProjectOpenProcessor;
import com.intellij.projectImport.ProjectAttachProcessor;
import floobits.common.*;
import floobits.dialogs.CreateAccount;
import floobits.impl.ContextImpl;
import floobits.utilities.Flog;
import floobits.utilities.IntelliBrowserOpener;
import floobits.utilities.SelectFolder;
import org.jetbrains.annotations.NotNull;

import java.awt.*;
import java.io.File;
import java.net.URI;

public class FloobitsApplication implements ApplicationComponent {
    public static FloobitsApplication self;
    private Boolean createAccount = true;

    public FloobitsApplication() {
        self = this;
    }

    public void initComponent() {
        BrowserOpener.replaceSingleton(new IntelliBrowserOpener());
        ApplicationInfo instance = ApplicationInfo.getInstance();
        IdeaPluginDescriptor plugin = PluginManager.getPlugin(PluginId.getId("com.floobits.unique.plugin.id"));
        createAccount = Bootstrap.bootstrap(instance.getVersionName(), instance.getMajorVersion(), instance.getMinorVersion(), plugin != null ? plugin.getVersion() : "???");
    }

    public void disposeComponent() {
        // TODO: insert component disposal logic here
    }

    public synchronized void projectOpened(ContextImpl context) {
        if (!createAccount) {
            return;
        }
        PersistentJson p = PersistentJson.getInstance();
        if (p.disable_account_creation) {
            context.statusMessage("Please create a Floobits account and/or make a ~/.floorc.json (https://floobits.com/help/floorc)");
            return;
        }
        createAccount = false;
        CreateAccount createAccountDialog = new CreateAccount(context.project);
        createAccountDialog.createCenterPanel();
        createAccountDialog.show();
    }

    @NotNull
    public String getComponentName() {
        return "FloobitsApplication";
    }

    public void joinWorkspace(final String url) {
        final FlooUrl f;
        try {
            f = new FlooUrl(url);
        } catch (Exception e) {
            Flog.errorMessage(String.format("Invalid url: %s", e), null);
            return;
        }
        SelectFolder.build(f.owner, f.workspace, new RunLater<String>() {
            @Override
            public void run(final String location) {
                Project projectForPath = getProject(location);
                if (projectForPath == null) {
                    Flog.errorMessage("The editor could not open the project :(", null);
                    return;
                }
                final ContextImpl context = FloobitsPlugin.getInstance(projectForPath).context;
                context.writeThread(new Runnable() {
                    @Override
                    public void run() {
                        context.project.save();
                        Window window = WindowManager.getInstance().suggestParentWindow(context.project);
                        if (window != null) {
                            window.toFront();
                        }
                        context.joinWorkspace(f, location, false, null);
                    }
                });
            }
        });

    }

    public void joinWorkspace(ContextImpl context, final FlooUrl flooUrl, final String location) {
        Project projectForPath = getProject(location);

        if (context == null || projectForPath != context.project) {
            if (projectForPath == null) {
                Flog.errorMessage("The editor could not open the project :(", null);
                return;
            }
            context = FloobitsPlugin.getInstance(projectForPath).context;
        }
        // not gonna work here
        final ContextImpl finalContext = context;
        context.writeThread(new Runnable() {
            @Override
            public void run() {
                Window window = WindowManager.getInstance().suggestParentWindow(finalContext.project);
                if (window != null) {
                    window.toFront();
                }
                finalContext.joinWorkspace(flooUrl, location, false, null);
            }
        });
    }

    public void joinWorkspace(final ContextImpl context, final String url) {
        final FlooUrl f;

        try {
            f = new FlooUrl(url);
        } catch (Throwable e) {
            Flog.errorMessage(String.format("Invalid url: %s", e), context.project);
            return;
        }

        PersistentJson persistentJson = PersistentJson.getInstance();
        Workspace workspace;
        try {
            workspace = persistentJson.workspaces.get(f.owner).get(f.workspace);
        } catch (Throwable e) {
            workspace = null;
        }
        if (workspace != null) {
            joinWorkspace(context, f, workspace.path);
            return;
        }
        if (context != null) { // Can be null if started from quick menu.
            FlooUrl flooUrl = DotFloo.read(context.project.getBasePath());
            if (flooUrl != null) {
                URI uri = URI.create(flooUrl.toString());
                URI normalizedURL = URI.create(url);

                if (uri.getPath().equals(normalizedURL.getPath())) {
                    joinWorkspace(context, flooUrl, context.project.getBasePath());
                    return;
                }
            }
        }

        SelectFolder.build(f.owner, f.workspace, new RunLater<String>() {
            @Override
            public void run(String path) {
                joinWorkspace(context, f, path);
            }
        });
    }

    private Project getProject(String path) {
        ProjectManager pm = ProjectManager.getInstance();
        Project[] openProjects = pm.getOpenProjects();
        for (Project project : openProjects) {
            if (path.equals(project.getBasePath())) {
                return project;
            }
        }
        VirtualFile file = LocalFileSystem.getInstance().findFileByIoFile(new File(path));
        Project openedProject;
        if (ProjectAttachProcessor.canAttachToProject() && file != null) {
            openedProject = PlatformProjectOpenProcessor.doOpenProject(file, null, false, -1, null, false);
        } else {
            openedProject = ProjectUtil.openOrImport(path, null, false);
        }
        if (openedProject == null) {
            try {
                String projectFilePath = ".idea/misc.xml";
                if (path.endsWith(projectFilePath)) {
                    Flog.error("Attempted to open the project misc.xml file instead of the directory.");
                    path = path.replace(projectFilePath, "");
                }
                openedProject = ProjectManager.getInstance().loadAndOpenProject(path);
            } catch (Throwable e) {
                Flog.error(e);
                API.uploadCrash(null, null, e);
                return null;
            }
        }
        // This is something Intellij does when a user opens a project from the menu:
        FileChooserUtil.setLastOpenedFile(openedProject, file);
        return openedProject;
    }

}