package p.studio.window;

import javafx.scene.layout.BorderPane;
import p.studio.Container;
import p.studio.controls.shell.*;
import p.studio.execution.StudioPlayStopCoordinator;
import p.studio.projectstate.ProjectLocalStudioSetup;
import p.studio.lsp.events.StudioWorkspaceSelectedEvent;
import p.studio.projectstate.ProjectLocalStudioState;
import p.studio.projects.ProjectReference;
import p.studio.projectsessions.StudioProjectSession;
import p.studio.utilities.i18n.I18n;
import p.studio.workspaces.WorkspaceHost;
import p.studio.workspaces.WorkspaceId;
import p.studio.workspaces.assets.AssetWorkspace;
import p.studio.workspaces.builder.ShipperWorkspace;
import p.studio.workspaces.debug.DebugWorkspace;

import java.util.List;

public final class MainView extends BorderPane {
    private final WorkspaceHost host = new WorkspaceHost();
    private final ProjectReference projectReference;
    private final StudioProjectSession projectSession;
    private final AssetWorkspace assetWorkspace;
    private final StudioWorkspaceRailControl<WorkspaceId> workspaceRail;
    private final StudioPlayStopCoordinator playStopCoordinator;
    private boolean initializing;
    private boolean workspaceLifecycleInitialized;

    public MainView(final StudioProjectSession projectSession) {
        initializing = true;
        this.projectSession = projectSession;
        this.projectReference = projectSession.projectReference();
        final ProjectLocalStudioState persistedState = projectSession.projectLocalStudioState();
        final ProjectLocalStudioSetup projectSetup = projectSession.projectLocalStudioSetup();
        final var menuBar = new StudioShellMenuBarControl();
        playStopCoordinator = new StudioPlayStopCoordinator(
                projectReference,
                projectSetup,
                projectSession.executionSession(),
                this::selectWorkspace);
        final var runSurface = new StudioRunSurfaceControl(
                projectSession.executionSession(),
                playStopCoordinator::play,
                playStopCoordinator::stop);
        setTop(new StudioShellTopBarControl(menuBar));

        assetWorkspace = new AssetWorkspace(projectReference);
        host.register(assetWorkspace);
        assetWorkspace.restoreProjectLocalState(persistedState);
        assetWorkspace.setStateChangedAction(this::persistProjectLocalState);
        host.register(new DebugWorkspace(projectReference, projectSession.executionSession()));
        host.register(new ShipperWorkspace(projectReference));

        workspaceRail = new StudioWorkspaceRailControl<>(
                List.of(
                        new StudioWorkspaceRailItem<>(WorkspaceId.ASSETS, "📦", Container.i18n().bind(I18n.WORKSPACE_ASSETS)),
                        new StudioWorkspaceRailItem<>(WorkspaceId.DEBUG, "🎮", Container.i18n().bind(I18n.WORKSPACE_DEBUG)),
                        new StudioWorkspaceRailItem<>(WorkspaceId.SHIPPER, "⚙️", Container.i18n().bind(I18n.WORKSPACE_SHIPPER))
                ),
                this::loadWorkspace);
        setLeft(workspaceRail);
        setCenter(host);
        setRight(new StudioRightUtilityPanelControl(
                runSurface,
                Container.i18n().bind(I18n.SHELL_ACTIVITY),
                new StudioActivityFeedControl(projectReference)));

        final WorkspaceId initialWorkspace = restoreInitialWorkspace(persistedState.openShellState());
        workspaceRail.select(initialWorkspace);
        loadWorkspace(initialWorkspace);
        workspaceLifecycleInitialized = true;
        initializing = false;
    }

    public ProjectReference projectReference() {
        return projectReference;
    }

    public StudioProjectSession projectSession() {
        return projectSession;
    }

    public void persistProjectLocalState() {
        if (initializing) {
            return;
        }
        final WorkspaceId selectedWorkspace = host.getCurrentWorkspaceId() == null ? WorkspaceId.ASSETS : host.getCurrentWorkspaceId();
        final ProjectLocalStudioState current = projectSession.projectLocalStudioState();
        projectSession.replaceProjectLocalStudioState(
                current.withOpenShellState(new ProjectLocalStudioState.OpenShellState(selectedWorkspace.name()))
                        .withShellLayout(new ProjectLocalStudioState.ShellLayout(
                                assetWorkspace.captureLayoutState())));
    }

    public void reapplyProjectLocalLayout() {
        assetWorkspace.reapplyPendingLayoutState();
    }

    public void close() {
        playStopCoordinator.shutdown();
        persistProjectLocalState();
        host.deactivateCurrentWorkspace();
    }

    private void loadWorkspace(WorkspaceId workspaceId) {
        host.change(workspaceId);
        if (workspaceLifecycleInitialized) {
            persistProjectLocalState();
            projectSession.saveProjectLocalStudioState();
        }
        Container.eventBus().publish(new StudioWorkspaceSelectedEvent(workspaceId));
    }

    private void selectWorkspace(final WorkspaceId workspaceId) {
        workspaceRail.select(workspaceId);
        loadWorkspace(workspaceId);
    }

    private WorkspaceId restoreInitialWorkspace(final ProjectLocalStudioState.OpenShellState openShellState) {
        if (openShellState.selectedWorkspaceId() == null) {
            return WorkspaceId.ASSETS;
        }
        try {
            return WorkspaceId.valueOf(openShellState.selectedWorkspaceId());
        } catch (IllegalArgumentException ignored) {
            return WorkspaceId.ASSETS;
        }
    }

}
