package com.foxx.androidcast.studio;

/*********************************************************************
 * SessionStudioApp.java
 * Created at: Mon 18 May 2026 18:26:28 +0200
 * Updated at: Wed 20 May 2026 15:17:13 +0200 by Anton Afanasyeu <a.afanasieff@gmail.com>
 * Commit: 5d8e82d2e60a21fff3138d2a394ee4e8b4c6dcb8
 * class SessionStudioApp
 * Contributors:
 *    - Anton Afanasyeu <a.afanasieff@gmail.com> (3 commits, 154 lines)
 *    - Cursor Agent (project assistant)
 * Digest: SHA256	92d8059db3ad304cc533ac1c765606f42a06a50f482508fe3d2abbb422292c94
**********************************************************************/
import javafx.application.Application;
import javafx.collections.ListChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

/**
 * Desktop session log viewer — open session_send_* / session_recv_* JSON, overlay charts.
 */
public class SessionStudioApp extends Application {

    private final List<SessionDocument> sessions = new ArrayList<>();
    private final SessionChartPane chartPane = new SessionChartPane();
    private final Label statusLabel = new Label("Open session_send_* / session_recv_* JSON from the device.");

    @Override
    public void start(Stage stage) {
        Button openBtn = new Button("Open sessions…");

        CheckBox metricBitrate = new CheckBox("Video bitrate");
        metricBitrate.setSelected(true);
        CheckBox metricLoss = new CheckBox("Packet loss %");
        CheckBox metricFps = new CheckBox("Encode FPS");

        ListView<String> sessionList = new ListView<>();
        sessionList.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        sessionList.setPrefHeight(100);

        Runnable refresh = () -> {
            List<SessionDocument> selected = selectedSessions(sessionList);
            SessionChartPane.Metric metric = SessionChartPane.Metric.BITRATE;
            if (metricLoss.isSelected()) {
                metric = SessionChartPane.Metric.LOSS;
            } else if (metricFps.isSelected()) {
                metric = SessionChartPane.Metric.ENCODE_FPS;
            } else if (metricBitrate.isSelected()) {
                metric = SessionChartPane.Metric.BITRATE;
            }
            chartPane.render(selected, metric);
        };

        metricBitrate.setOnAction(e -> {
            if (metricBitrate.isSelected()) {
                metricLoss.setSelected(false);
                metricFps.setSelected(false);
            }
            refresh.run();
        });
        metricLoss.setOnAction(e -> {
            if (metricLoss.isSelected()) {
                metricBitrate.setSelected(false);
                metricFps.setSelected(false);
            }
            refresh.run();
        });
        metricFps.setOnAction(e -> {
            if (metricFps.isSelected()) {
                metricBitrate.setSelected(false);
                metricLoss.setSelected(false);
            }
            refresh.run();
        });
        sessionList.getSelectionModel().getSelectedIndices()
                .addListener((ListChangeListener<Integer>) c -> refresh.run());

        HBox toolbar = new HBox(12, openBtn, metricBitrate, metricLoss, metricFps);
        toolbar.setStyle("-fx-padding: 8;");

        Label hint = new Label("Scroll wheel over chart to zoom X+Y. Hover a line for values. RTT removed — use loss % or bitrate.");
        hint.setStyle("-fx-text-fill: #888; -fx-font-size: 11;");

        VBox top = new VBox(8, toolbar, hint, sessionList, statusLabel);
        top.setStyle("-fx-padding: 8;");

        BorderPane root = new BorderPane();
        root.setTop(top);
        root.setCenter(chartPane);
        openBtn.setOnAction(e -> {
            openFiles(stage);
            sessionList.getItems().clear();
            for (SessionDocument doc : sessions) {
                sessionList.getItems().add(doc.path);
            }
            if (!sessions.isEmpty()) {
                sessionList.getSelectionModel().selectAll();
            }
            refresh.run();
        });

        stage.setTitle("Android Cast Session Studio");
        stage.setScene(new Scene(root, 960, 640));
        stage.show();
    }

    private List<SessionDocument> selectedSessions(ListView<String> list) {
        List<SessionDocument> out = new ArrayList<>();
        for (int idx : list.getSelectionModel().getSelectedIndices()) {
            if (idx >= 0 && idx < sessions.size()) {
                out.add(sessions.get(idx));
            }
        }
        if (out.isEmpty() && !sessions.isEmpty()) {
            out.addAll(sessions);
        }
        return out;
    }

    private void openFiles(Stage stage) {
        FileChooser chooser = new FileChooser();
        chooser.setTitle("Session JSON files");
        chooser.getExtensionFilters().add(
                new FileChooser.ExtensionFilter("Session JSON", "*.json"));
        List<File> files = chooser.showOpenMultipleDialog(stage);
        if (files == null || files.isEmpty()) {
            return;
        }
        sessions.clear();
        for (File f : files) {
            try {
                sessions.add(SessionDocument.load(Path.of(f.getAbsolutePath())));
            } catch (Exception ex) {
                statusLabel.setText("Failed: " + f.getName() + " — " + ex.getMessage());
                return;
            }
        }
        statusLabel.setText("Loaded " + sessions.size() + " session file(s). Select rows to overlay.");
    }

    public static void main(String[] args) {
        launch(args);
    }
}
