import struct
import time
import threading
import os
import sys
from PyQt6.QtWidgets import (
    QApplication, QWidget, QLabel, QGridLayout, QVBoxLayout,
    QGroupBox
)
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QIcon, QPixmap

# Change working directory to script's directory
os.chdir(os.path.dirname(os.path.abspath(sys.argv[0])))

# Constants (removed acceleration related IDs)
ID_TIMESTAMP = 0x01
ID_EFIELD_CH1 = 0x02
ID_BATTERY_VOLT = 0x09
ID_3V3_VOLT = 0x0A
ID_1V5_VOLT = 0x0B
ID_EFIELD_CH2 = 0x1B
ID_EFIELD_CH3 = 0x1C
ID_3V_RTC = 0x0C
ID_TEMP = 0x0D
ID_STATUS = 0x11
ID_SDCARD_STATUS = 0x81  # ID 129 in decimal


class DataGUI(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("MBARI CSEM Datalogger GUI")
        self.setWindowIcon(QIcon("MBARI_logo.png"))  # Set window icon here
        self.labels = {}
        self.status_fields = [
            "31: RemoteSupport (0=disconnected, 1=connected)",
            "30–29: EF Gain Ch3",
            "28–27: EF Gain Ch2",
            "26–12: Atomic Clock Alarm",
            "11–8: Atomic Clock Status",
            "7: EF SimData (0=normal, 1=sim)",
            "6: LSB output (0=off, 1=on)",
            "5–4: EF Gain Ch1",
            "3: Watchdog (0=off, 1=on)",
            "2–1: Start-Mode",
            "0: Logging (0=off, 1=on)"
        ]
        self.init_ui()
        self.start_reader_thread()

    def create_group(self, title, items):
        group_box = QGroupBox(title)
        layout = QGridLayout()
        for i, name in enumerate(items):
            label_name = QLabel(name)
            label_name.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
            label_value = QLabel("—")
            label_value.setMinimumWidth(150)
            layout.addWidget(label_name, i, 0)
            layout.addWidget(label_value, i, 1)
            self.labels[name] = label_value
        group_box.setLayout(layout)
        return group_box

    def init_ui(self):
        main_layout = QVBoxLayout()

        # Time Section in a GroupBox
        time_group = QGroupBox("Time")
        time_layout = QGridLayout()
        labels = ["PC Time", "Timestamp"]
        for i, label in enumerate(labels):
            label_widget = QLabel(label)
            label_widget.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
            value_label = QLabel("—")
            value_label.setMinimumWidth(150)
            self.labels[label] = value_label
            time_layout.addWidget(label_widget, i, 0)
            time_layout.addWidget(value_label, i, 1)
        time_group.setLayout(time_layout)
        main_layout.addWidget(time_group)

        # Add sections
        main_layout.addWidget(self.create_group("E-Field Channels", [
            "E-field Ch1 (uV)", "E-field Ch2 (uV)", "E-field Ch3 (uV)"
        ]))
        main_layout.addWidget(self.create_group("Voltages", [
            "Battery Voltage (V)", "3.3V RTC (V)", "3.3V Rail (V)", "1.5V Rail (V)"
        ]))
        main_layout.addWidget(self.create_group("Temperature", [
            "Temperature (°C)"
        ]))
        main_layout.addWidget(self.create_group("Status Overview", [
            "Status (Decimal)", "Status (Hex)"
        ]))
        main_layout.addWidget(self.create_group("Status Bitfields", self.status_fields))

        # Add SD card section
        main_layout.addWidget(self.create_group("SD Card Status", [
            "Card Size (MB)", "Card Used (MB)"
        ]))

        # Green/red indicator for Logging
        self.logging_indicator = QLabel("—")
        self.logging_indicator.setAlignment(Qt.AlignmentFlag.AlignCenter)
        main_layout.addWidget(self.logging_indicator)

        self.setLayout(main_layout)

    def start_reader_thread(self):
        self.thread = threading.Thread(target=self.read_data_loop, daemon=True)
        self.thread.start()

    def update_label(self, key, value):
        if key in self.labels:
            self.labels[key].setText(str(value))

    def update_logging_indicator(self, logging_status):
        if logging_status == 1:
            self.logging_indicator.setText("Logging ON")
            self.logging_indicator.setStyleSheet("background-color: green;")
        else:
            self.logging_indicator.setText("Logging OFF")
            self.logging_indicator.setStyleSheet("background-color: red;")

    def read_data_loop(self):
        efield_data = {}
        last_voltages = {
            ID_BATTERY_VOLT: 0.0,
            ID_3V3_VOLT: 0.0,
            ID_1V5_VOLT: 0.0,
            ID_3V_RTC: 0.0,
            ID_TEMP: 0.0,
        }
        status_val = 0
        current_timestamp = None
        sd_card_size = 0.0
        sd_card_used = 0.0

        try:
            with open("Test.B162", "rb") as f:
                while True:
                    header = f.read(1)
                    if not header:
                        break

                    data_id = header[0]
                    data_bytes = f.read(4)
                    if len(data_bytes) < 4:
                        break

                    if data_id == ID_TIMESTAMP:
                        ts = struct.unpack('<I', data_bytes)[0]
                        current_timestamp = ts

                        pc_time = time.time()
                        self.update_label("PC Time", self.format_time(pc_time))
                        self.update_label("Timestamp", self.format_time(ts))
                        self.update_label("E-field Ch1 (uV)", f"{efield_data.get(ID_EFIELD_CH1, 0.0):.4f}")
                        self.update_label("E-field Ch2 (uV)", f"{efield_data.get(ID_EFIELD_CH2, 0.0):.4f}")
                        self.update_label("E-field Ch3 (uV)", f"{efield_data.get(ID_EFIELD_CH3, 0.0):.4f}")
                        self.update_label("Battery Voltage (V)", f"{last_voltages[ID_BATTERY_VOLT]:.3f}")
                        self.update_label("3.3V RTC (V)", f"{last_voltages[ID_3V_RTC]:.3f}")
                        self.update_label("3.3V Rail (V)", f"{last_voltages[ID_3V3_VOLT]:.3f}")
                        self.update_label("1.5V Rail (V)", f"{last_voltages[ID_1V5_VOLT]:.3f}")
                        
                        # Corrected temperature reading
                        temperature = last_voltages[ID_TEMP] 
                        self.update_label("Temperature (°C)", f"{temperature:.2f}")
                        
                        self.update_label("Status (Decimal)", str(status_val))
                        self.update_label("Status (Hex)", hex(status_val))

                        # Check and update logging status
                        logging_status = status_val & 0x1
                        self.update_logging_indicator(logging_status)

                        # Update SD card info
                        self.update_label("Card Size (MB)", f"{sd_card_size:.2f}")
                        self.update_label("Card Used (MB)", f"{sd_card_used:.2f}")

                        bitfields = [
                            (status_val >> 31) & 0x1,
                            (status_val >> 29) & 0x3,
                            (status_val >> 27) & 0x3,
                            (status_val >> 12) & 0x7FFF,
                            (status_val >> 8) & 0xF,
                            (status_val >> 7) & 0x1,
                            (status_val >> 6) & 0x1,
                            (status_val >> 4) & 0x3,
                            (status_val >> 3) & 0x1,
                            (status_val >> 1) & 0x3,
                            status_val & 0x1
                        ]
                        for i, val in enumerate(bitfields):
                            self.update_label(self.status_fields[i], str(val))

                        time.sleep(1)

                    elif data_id == ID_SDCARD_STATUS:
                        # Read SD card size and used space (2 Floats, 8 bytes total)
                        sd_card_data = struct.unpack('<2f', data_bytes)
                        sd_card_size, sd_card_used = sd_card_data

                    elif data_id in (ID_EFIELD_CH1, ID_EFIELD_CH2, ID_EFIELD_CH3):
                        val = struct.unpack('<f', data_bytes)[0]
                        efield_data[data_id] = val

                    elif data_id in (ID_BATTERY_VOLT, ID_3V3_VOLT, ID_1V5_VOLT, ID_3V_RTC, ID_TEMP):
                        val = struct.unpack('<f', data_bytes)[0]
                        last_voltages[data_id] = val

                    elif data_id == ID_STATUS:
                        status_val = struct.unpack('<I', data_bytes)[0]

                    elif data_id == 13:
                        temperature = struct.unpack('<f', data_bytes)[0]
                        print(f"Temperature = {temperature:.2f}degreeC")

        except FileNotFoundError:
            print("File Test.B162 not found.")

    def format_time(self, unix_time):
        return time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(unix_time))

if __name__ == "__main__":
    app = QApplication([])
    gui = DataGUI()
    gui.show()
    app.exec()
