package application;

import com.fazecast.jSerialComm.SerialPort;
import com.fazecast.jSerialComm.SerialPortDataListener;
import com.fazecast.jSerialComm.SerialPortEvent;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextArea;

public class PrimaryController {

    // =========================================================================
    // GLOBAL DATA SETTINGS (Team Area for Sending)
    // =========================================================================
    // Edit these strings to change what the buttons send to the hardware.
    public String COMMAND_01 = "START_ENGINE";
    public String COMMAND_02 = "STOP_ENGINE";
    public String COMMAND_TEST = "PING";

    // =========================================================================
    // UI CONTROLS (@FXML)
    // =========================================================================
    @FXML private ComboBox<String> selComPort;
    @FXML private ComboBox<Integer> selBaudRate;
    @FXML private Button btnConnect;
    @FXML private TextArea displaySend01;
    @FXML private TextArea displayRec01;

    // --- INTERNAL VARIABLES ---
    private SerialPort activePort;
    private boolean isConnected = false;

    @FXML
    public void initialize() {
        // Setup Baud Rates
        selBaudRate.setItems(FXCollections.observableArrayList(9600, 57600, 115200, 230400, 500000, 1000000));
        selBaudRate.getSelectionModel().selectFirst();

        // Refresh port list when dropdown is clicked
        selComPort.setOnShowing(e -> {
            selComPort.getItems().clear();
            for (SerialPort port : SerialPort.getCommPorts()) {
                selComPort.getItems().add(port.getSystemPortName());
            }
        });
    }

    // =========================================================================
    // CONNECTION LOGIC
    // =========================================================================
    @FXML
    private void handleConnect() {
        if (!isConnected) {
            try {
                if (selComPort.getValue() == null) return;

                activePort = SerialPort.getCommPort(selComPort.getValue());
                activePort.setBaudRate(selBaudRate.getValue());
                
                // Hardware safety timeouts
                activePort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 0, 0);

                if (activePort.openPort()) {
                    isConnected = true;
                    btnConnect.setText("Disconnect");
                    btnConnect.setStyle("-fx-background-color: #90EE90;"); // Green
                    setupDataListener();
                }
            } catch (Exception ex) {
                displaySend01.appendText("Connection Error: " + ex.getMessage() + "\n");
            }
        } else {
            disconnect();
        }
    }

    private void disconnect() {
        if (activePort != null) {
            activePort.removeDataListener();
            activePort.closePort();
        }
        isConnected = false;
        btnConnect.setText("Connect");
        btnConnect.setStyle(""); 
    }

    private void setupDataListener() {
        activePort.addDataListener(new SerialPortDataListener() {
            @Override
            public int getListeningEvents() { 
                return SerialPort.LISTENING_EVENT_DATA_AVAILABLE | 
                       SerialPort.LISTENING_EVENT_PORT_DISCONNECTED; 
            }

            @Override
            public void serialEvent(SerialPortEvent event) {
                // Check if FTDI was unplugged
                if (event.getEventType() == SerialPort.LISTENING_EVENT_PORT_DISCONNECTED) {
                    Platform.runLater(() -> {
                        displayRec01.appendText("\n[SYSTEM]: Hardware Disconnected.\n");
                        disconnect();
                    });
                }
                
                // Check for incoming data
                else if (event.getEventType() == SerialPort.LISTENING_EVENT_DATA_AVAILABLE) {
                    if (activePort == null || !activePort.isOpen()) return;
                    
                    byte[] newData = new byte[activePort.bytesAvailable()];
                    int numRead = activePort.readBytes(newData, newData.length);
                    if (numRead > 0) {
                        String message = new String(newData, 0, numRead);
                        // Hand off to processing area
                        processIncomingData(message);
                    }
                }
            }
        });
    }

    // =========================================================================
    // SENDING LOGIC (Using Global Variables)
    // =========================================================================
    @FXML
    private void handleSend01() { 
        sendData(COMMAND_01); 
    }

    @FXML
    private void handleSend02() { 
        sendData(COMMAND_02); 
    }

    private void sendData(String text) {
        if (isConnected && activePort.isOpen()) {
            byte[] bytes = (text + "\n").getBytes();
            activePort.writeBytes(bytes, bytes.length);
            displaySend01.appendText("Sent: " + text + "\n");
        } else {
            displaySend01.appendText("Error: Port not connected!\n");
        }
    }

    @FXML private void handleClear01() { displaySend01.clear(); }
    @FXML private void handleClear02() { displayRec01.clear(); }

    // =========================================================================
    // DATA PROCESSING SECTION (Teammate Area for Receiving)
    // =========================================================================
    private void processIncomingData(String rawData) {
        // Clean the data
        String cleanData = rawData.trim();

        /* TEAMMATES: Add your parsing logic here */

        Platform.runLater(() -> {
            displayRec01.appendText(cleanData + "\n");
            displayRec01.selectEnd();
            displayRec01.deselect();
        });
    }
}