package p.studio.workspaces.debug;

import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import p.studio.Container;
import p.studio.execution.StudioExecutionSessionService;
import p.studio.execution.StudioExecutionSnapshot;
import p.studio.execution.StudioExecutionState;
import p.studio.projects.ProjectReference;
import p.studio.utilities.events.EventSubscription;
import p.studio.utilities.i18n.I18n;
import p.studio.workspaces.Workspace;
import p.studio.workspaces.WorkspaceId;

public final class DebugWorkspace extends Workspace {
    private final BorderPane root = new BorderPane();
    private final StudioExecutionSessionService executionSessionService;
    private final Label statusValue = new Label();
    private final TextArea logs = new TextArea();
    private EventSubscription sessionSubscription;

    public DebugWorkspace(
            final ProjectReference projectReference,
            final StudioExecutionSessionService executionSessionService) {
        super(projectReference);
        this.executionSessionService = executionSessionService;
        root.getStyleClass().add("debug-workspace");
        root.setPadding(new Insets(16));
        root.setTop(buildStatusPane());
        root.setCenter(buildLogsPane());
    }

    @Override
    public WorkspaceId workspaceId() {
        return WorkspaceId.DEBUG;
    }

    @Override
    public I18n title() {
        return I18n.WORKSPACE_DEBUG;
    }

    @Override
    public Node rootNode() {
        return root;
    }

    @Override
    public void load() {
        if (sessionSubscription != null) {
            return;
        }
        sessionSubscription = executionSessionService.subscribe(this::renderSnapshot);
    }

    @Override
    public void unLoad() {
        if (sessionSubscription == null) {
            return;
        }
        sessionSubscription.unsubscribe();
        sessionSubscription = null;
    }

    private Node buildStatusPane() {
        final Label title = new Label();
        title.textProperty().bind(Container.i18n().bind(I18n.WORKSPACE_DEBUG_STATE));
        title.getStyleClass().add("studio-section-title");
        statusValue.getStyleClass().add("studio-debug-status-value");
        return new HBox(12, title, statusValue);
    }

    private Node buildLogsPane() {
        logs.setEditable(false);
        logs.setWrapText(true);
        logs.setMinHeight(360);
        final TitledPane pane = new TitledPane();
        pane.textProperty().bind(Container.i18n().bind(I18n.WORKSPACE_DEBUG_LOGS));
        pane.setContent(logs);
        pane.setCollapsible(false);
        pane.setExpanded(true);
        return pane;
    }

    private void renderSnapshot(final StudioExecutionSnapshot snapshot) {
        if (Platform.isFxApplicationThread()) {
            applySnapshot(snapshot);
            return;
        }
        Platform.runLater(() -> applySnapshot(snapshot));
    }

    private void applySnapshot(final StudioExecutionSnapshot snapshot) {
        final DebugWorkspaceProjection projection = DebugWorkspaceProjection.from(snapshot);
        statusValue.setText(Container.i18n().text(statusText(projection.state())));
        logs.setText(String.join(System.lineSeparator(), projection.renderedLogs()));
    }

    private I18n statusText(final StudioExecutionState state) {
        return switch (state) {
            case IDLE -> I18n.WORKSPACE_DEBUG_STATUS_IDLE;
            case PREPARING -> I18n.WORKSPACE_DEBUG_STATUS_PREPARING;
            case PREPARE_FAILED -> I18n.WORKSPACE_DEBUG_STATUS_PREPARE_FAILED;
            case CONNECTING -> I18n.WORKSPACE_DEBUG_STATUS_CONNECTING;
            case RUNNING -> I18n.WORKSPACE_DEBUG_STATUS_RUNNING;
            case RUNTIME_FAILED -> I18n.WORKSPACE_DEBUG_STATUS_RUNTIME_FAILED;
            case STOPPED -> I18n.WORKSPACE_DEBUG_STATUS_STOPPED;
        };
    }
}
