#!/usr/bin/env python3
"""
vzug-e-hinge Main Application
==============================
Entry point for the integrated test and control system.

Integrates:
- Session management
- UART control
- I2C control
- UART Logger
- I2C Logger
- Graph visualization
- Test profile execution

Author: Kynsight
Version: 1.0.0
"""

import sys
import os
from pathlib import Path

# Force X11 backend for Qt (Wayland workaround)
# os.environ['QT_QPA_PLATFORM'] = 'xcb'

from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QTabWidget, QWidget, QVBoxLayout,
    QHBoxLayout, QLabel, QMenuBar, QMenu, QMessageBox, QStatusBar
)
from PyQt6.QtCore import Qt, QTimer
from PyQt6.QtGui import QAction

# Import database
from database.init_database import DatabaseManager

# Import widgets
from session_widget import SessionWidget
from configure_interface_widget import ConfigureInterfaceWidget
from configure_session_widget import ConfigureSessionWidget
from uart.uart_integrated_widget import UARTControlWidget
from i2c.i2c_integrated_widget import I2CControlWidget
from graph.graph_kit.graph_core_widget import GraphWidget


class MainWindow(QMainWindow):
    """
    Main application window with tabbed interface.
    
    Tabs:
    - Session: Control panel, command execution, profile management
    - UART: Direct UART control
    - UART Logger: UART logging interface
    - I2C: Direct I2C control
    - I2C Logger: I2C logging interface
    - Graph: Data visualization
    """
    
    def __init__(self, db_path: str = "./database/ehinge.db"):
        super().__init__()
        
        self.db_path = db_path
        self.db_manager = None
        
        # Initialize database
        self._init_database()
        
        # Setup UI
        self._init_ui()
        
        # Setup session manager
        self._init_session_manager()
        
        # Setup connections
        self._setup_connections()
        
        # Status update timer
        self.status_timer = QTimer()
        self.status_timer.timeout.connect(self._update_status)
        self.status_timer.start(1000)  # Update every second
    
    def _init_database(self):
        """Initialize database connection."""
        self.db_manager = DatabaseManager(self.db_path)
        
        # Check if database exists
        if not os.path.exists(self.db_path):
            reply = QMessageBox.question(
                self,
                "Database Not Found",
                f"Database not found at:\n{self.db_path}\n\nCreate new database?",
                QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
            )
            
            if reply == QMessageBox.StandardButton.Yes:
                success = self.db_manager.initialize_database()
                if not success:
                    QMessageBox.critical(
                        self,
                        "Database Error",
                        "Failed to create database. Application cannot continue."
                    )
                    sys.exit(1)
            else:
                sys.exit(0)
        else:
            # Connect to existing database
            if not self.db_manager.connect():
                QMessageBox.critical(
                    self,
                    "Database Error",
                    "Failed to connect to database. Application cannot continue."
                )
                sys.exit(1)
    
    def _init_ui(self):
        """Initialize user interface."""
        self.setWindowTitle("vzug-e-hinge Test & Control System")
        self.setGeometry(100, 100, 1400, 900)
        
        # Central widget with tabs
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        layout = QVBoxLayout()
        central_widget.setLayout(layout)
        
        # Session info bar (shows current session)
        self.session_info_bar = self._create_session_info_bar()
        layout.addWidget(self.session_info_bar)
        
        # Tab widget
        self.tabs = QTabWidget()
        layout.addWidget(self.tabs)
        
        # Create placeholder tabs (will be replaced with actual widgets)
        self._create_tabs()
        
        # Connect tab change to refresh profiles
        self.tabs.currentChanged.connect(self._on_tab_changed)
        
        # Menu bar
        self._create_menu_bar()
        
        # Status bar
        self.status_bar = QStatusBar()
        self.setStatusBar(self.status_bar)
        self.status_bar.showMessage("Ready")
    
    def _create_session_info_bar(self) -> QWidget:
        """Create session information bar at top."""
        widget = QWidget()
        widget.setStyleSheet("background-color: #1e1e1e; padding: 5px;")
        
        layout = QHBoxLayout()
        widget.setLayout(layout)
        
        # Session info
        self.lbl_session_name = QLabel("Session: None")
        self.lbl_session_name.setStyleSheet("color: #ffffff; font-weight: bold;")
        layout.addWidget(self.lbl_session_name)
        
        layout.addStretch()
        
        # Status indicator
        self.lbl_session_status = QLabel("Status: Idle")
        self.lbl_session_status.setStyleSheet("color: #00ff00;")
        layout.addWidget(self.lbl_session_status)
        
        # Run counter
        self.lbl_run_count = QLabel("Runs: 0")
        self.lbl_run_count.setStyleSheet("color: #ffffff;")
        layout.addWidget(self.lbl_run_count)
        
        # Database size
        self.lbl_db_size = QLabel("DB: 0%")
        self.lbl_db_size.setStyleSheet("color: #00ff00;")
        layout.addWidget(self.lbl_db_size)
        
        return widget
    
    def _create_tabs(self):
        """Create tab widgets."""
        # Tab 1: Session Control (integrate SessionWidget)
        try:
            from session_widget import SessionWidget
            self.session_widget = SessionWidget(self.db_manager)
            self.tabs.addTab(self.session_widget, "Session")
        except ImportError as e:
            # Fallback to placeholder if SessionWidget not available
            print(f"Warning: SessionWidget not available: {e}")
            self.tab_session = self._create_placeholder_tab("Session Control")
            self.tabs.addTab(self.tab_session, "Session")
            self.session_widget = None
        
        # Tab 2: Configure Session Profiles
        try:
            from configure_session_widget import ConfigureSessionWidget
            self.configure_session_widget = ConfigureSessionWidget(self.db_manager)
            self.tabs.addTab(self.configure_session_widget, "Configure Session")
        except ImportError as e:
            print(f"Warning: ConfigureSessionWidget not available: {e}")
            self.tab_configure_session = self._create_placeholder_tab("Configure Session")
            self.tabs.addTab(self.tab_configure_session, "Configure Session")
            self.configure_session_widget = None
        
        # Tab 3: Configure Interface Profiles
        try:
            from configure_interface_widget import ConfigureInterfaceWidget
            self.configure_interface_widget = ConfigureInterfaceWidget(self.db_manager)
            self.tabs.addTab(self.configure_interface_widget, "Configure Interface")
        except ImportError as e:
            print(f"Warning: ConfigureInterfaceWidget not available: {e}")
            self.tab_configure_interface = self._create_placeholder_tab("Configure Interface")
            self.tabs.addTab(self.tab_configure_interface, "Configure Interface")
            self.configure_interface_widget = None
        
        # Tab 4: UART (integrated: table + core)
        try:
            from uart.uart_integrated_widget import UARTControlWidget
            self.uart_widget = UARTControlWidget(self.db_manager.get_connection())
            self.tabs.addTab(self.uart_widget, "UART")
        except ImportError as e:
            print(f"UART widget import error: {e}")
            self.tab_uart = self._create_placeholder_tab("UART Control")
            self.tabs.addTab(self.tab_uart, "UART")
            self.uart_widget = None
        
        
        # Tab 5: I2C (integrated: table + core)
        try:
            from i2c.i2c_integrated_widget import I2CControlWidget
            self.i2c_widget = I2CControlWidget(self.db_manager.get_connection())
            self.tabs.addTab(self.i2c_widget, "I2C")
        except ImportError as e:
            print(f"I2C widget import error: {e}")
            self.tab_i2c = self._create_placeholder_tab("I2C Control")
            self.tabs.addTab(self.tab_i2c, "I2C")
            self.i2c_widget = None
        
        # Tab 6: Graph
        try:
            self.graph_widget = GraphWidget(db_path=self.db_path)
            self.tabs.addTab(self.graph_widget, "Graph")
        except Exception as e:
            print(f"[WARN] Failed to load Graph widget: {e}")
            self.tab_graph = self._create_placeholder_tab("Graph Visualization\n(Error loading)")
            self.tabs.addTab(self.tab_graph, "Graph")
            self.graph_widget = None
    
    def _create_placeholder_tab(self, title: str) -> QWidget:
        """Create placeholder tab widget."""
        widget = QWidget()
        layout = QVBoxLayout()
        widget.setLayout(layout)
        
        label = QLabel(f"{title}\n\n(Coming soon...)")
        label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        label.setStyleSheet("font-size: 16pt; color: #888888;")
        layout.addWidget(label)
        
        return widget
    
    def _create_menu_bar(self):
        """Create menu bar."""
        menubar = self.menuBar()
        
        # File menu
        file_menu = menubar.addMenu("&File")
        
        action_new_session = QAction("&New Session", self)
        action_new_session.setShortcut("Ctrl+N")
        action_new_session.triggered.connect(self._on_new_session)
        file_menu.addAction(action_new_session)
        
        action_end_session = QAction("&End Session", self)
        action_end_session.setShortcut("Ctrl+E")
        action_end_session.triggered.connect(self._on_end_session)
        file_menu.addAction(action_end_session)
        
        file_menu.addSeparator()
        
        action_export_session = QAction("E&xport Session...", self)
        action_export_session.triggered.connect(self._on_export_session)
        file_menu.addAction(action_export_session)
        
        file_menu.addSeparator()
        
        action_exit = QAction("E&xit", self)
        action_exit.setShortcut("Ctrl+Q")
        action_exit.triggered.connect(self.close)
        file_menu.addAction(action_exit)
        
        # Config menu
        config_menu = menubar.addMenu("&Config")
        
        action_uart_config = QAction("&UART Configuration...", self)
        action_uart_config.triggered.connect(self._on_uart_config)
        config_menu.addAction(action_uart_config)
        
        action_i2c_config = QAction("&I2C Configuration...", self)
        action_i2c_config.triggered.connect(self._on_i2c_config)
        config_menu.addAction(action_i2c_config)
        
        action_debugger_config = QAction("&Debugger Configuration...", self)
        action_debugger_config.triggered.connect(self._on_debugger_config)
        config_menu.addAction(action_debugger_config)
        
        config_menu.addSeparator()
        
        action_gui_profile = QAction("&GUI Profile...", self)
        action_gui_profile.triggered.connect(self._on_gui_profile)
        config_menu.addAction(action_gui_profile)
        
        # Profiles menu
        profiles_menu = menubar.addMenu("&Profiles")
        
        action_manage_profiles = QAction("&Manage Test Profiles...", self)
        action_manage_profiles.triggered.connect(self._on_manage_profiles)
        profiles_menu.addAction(action_manage_profiles)
        
        action_new_profile = QAction("&New Profile...", self)
        action_new_profile.triggered.connect(self._on_new_profile)
        profiles_menu.addAction(action_new_profile)
        
        # Database menu
        database_menu = menubar.addMenu("&Database")
        
        action_vacuum = QAction("&Vacuum Database", self)
        action_vacuum.triggered.connect(self._on_vacuum_database)
        database_menu.addAction(action_vacuum)
        
        action_db_info = QAction("Database &Info...", self)
        action_db_info.triggered.connect(self._on_database_info)
        database_menu.addAction(action_db_info)
        
        database_menu.addSeparator()
        
        action_cleanup = QAction("&Cleanup Old Data...", self)
        action_cleanup.triggered.connect(self._on_cleanup_data)
        database_menu.addAction(action_cleanup)
        
        # Help menu
        help_menu = menubar.addMenu("&Help")
        
        action_about = QAction("&About", self)
        action_about.triggered.connect(self._on_about)
        help_menu.addAction(action_about)
        
        action_docs = QAction("&Documentation", self)
        action_docs.triggered.connect(self._on_documentation)
        help_menu.addAction(action_docs)
    
    def _init_session_manager(self):
        """Initialize session manager (coordination logic)."""
        # NOTE: Session management is now integrated into SessionWidget
        # The Session class is instantiated by SessionWidget internally
        # No need for separate SessionManager anymore
        self.session_manager = None
    
    def _setup_connections(self):
        """Setup signal/slot connections between components."""
        # NOTE: Session management is now self-contained in SessionWidget
        # All signals/slots are handled internally by the widget
        # Main window just needs to monitor session state if desired
        
        if self.session_widget:
            # Connect to session widget's session object signals for monitoring
            try:
                self.session_widget.session.session_started.connect(self._on_session_started_internal)
                self.session_widget.session.session_finished.connect(self._on_session_finished_internal)
                self.session_widget.session.status_changed.connect(self._on_session_status_changed_internal)
            except Exception as e:
                print(f"Warning: Could not connect to session signals: {e}")

        # Connect UART widget TX/RX to Session widget's data monitor
        if hasattr(self, 'uart_widget') and self.uart_widget and self.session_widget:
            try:
                # Connect TX signal (bytes) → convert to hex string → display
                self.uart_widget.uart_core.data_sent.connect(
                    lambda data: self.session_widget._on_raw_data_received("TX", data.hex(' ').upper())
                )
                # Connect RX signal (bytes, info) → convert to hex string → display
                self.uart_widget.uart_core.data_received_display.connect(
                    lambda data, info: self.session_widget._on_raw_data_received("RX", data.hex(' ').upper())
                )
                print("[Main] Connected UART widget TX/RX to Session data monitor")
            except Exception as e:
                print(f"Warning: Could not connect UART signals to data monitor: {e}")
    
    # =========================================================================
    # Signal Handlers - Session Widget Actions
    # =========================================================================
    
    # =========================================================================
    # OLD Signal Handlers - NO LONGER USED (kept for reference)
    # Session management is now self-contained in SessionWidget
    # =========================================================================
    
    # def _on_execute_command_requested(self, command_type: str, command_id: int):
    #     """Handle execute command request from session widget."""
    #     # NO LONGER USED
    #     pass
    
    # def _on_execute_profile_requested(self, profile_id: int):
    #     """Handle execute profile request from session widget."""
    #     # NO LONGER USED
    #     pass
    
    # def _on_pause_profile_requested(self):
    #     """Handle pause profile request."""
    #     # NO LONGER USED
    #     pass
    
    # def _on_resume_profile_requested(self):
    #     """Handle resume profile request."""
    #     # NO LONGER USED
    #     pass
    
    # def _on_abort_profile_requested(self):
    #     """Handle abort profile request."""
    #     # NO LONGER USED
    #     pass
    
    # def _on_session_created(self, session_id: str):
    #     """Handle session created."""
    #     # NO LONGER USED
    #     pass
    
    # def _on_session_ended(self, session_id: str, status: str):
    #     """Handle session ended."""
    #     # NO LONGER USED
    #     pass
        self.lbl_session_status.setText("Status: Idle")
        self.lbl_session_status.setStyleSheet("color: #888888;")
    
    # def _on_run_started(self, session_id: str, run_no: int):
    #     """Handle run started."""
    #     # NO LONGER USED
    #     pass
    
    # def _on_run_completed(self, session_id: str, run_no: int, status: str):
    #     """Handle run completed."""
    #     # NO LONGER USED
    #     pass
    
    # def _on_profile_step_changed(self, current_repeat: int, current_step: int):
    #     """Handle profile step changed."""
    #     # NO LONGER USED
    #     pass
    
    # =========================================================================
    # Internal Session Monitoring (from new Session class)
    # =========================================================================
    
    def _on_session_started_internal(self, session_id: str):
        """Handle session started (internal monitoring)."""
        if self.session_widget:
            session_name = self.session_widget.session.get_session_name()
            self.lbl_session_name.setText(f"Session: {session_name}")
            self.lbl_session_status.setText("Status: Running")
            self.lbl_session_status.setStyleSheet("color: #00ff00;")
            self.status_bar.showMessage(f"Session started: {session_id}")
    
    def _on_session_finished_internal(self):
        """Handle session finished (internal monitoring)."""
        self.lbl_session_status.setText("Status: Finished")
        self.lbl_session_status.setStyleSheet("color: #00ff00;")
        self.status_bar.showMessage("Session completed successfully")
    
    def _on_session_status_changed_internal(self, status_text: str):
        """Handle session status changes (internal monitoring)."""
        # Update status bar with session status
        self.status_bar.showMessage(status_text)
    
    def _update_status(self):
        """Update status bar and session info (called every second)."""
        # Update database size
        try:
            size_bytes, percentage, status = self.db_manager.check_size()
            
            color = "#00ff00"  # Green
            if status == "warning":
                color = "#ffaa00"  # Orange
            elif status == "critical":
                color = "#ff0000"  # Red
            
            self.lbl_db_size.setText(f"DB: {percentage:.1f}%")
            self.lbl_db_size.setStyleSheet(f"color: {color};")
        except:
            pass
        
        # Update run count from session widget
        if self.session_widget and self.session_widget.session:
            try:
                # Get current session from widget
                session_id = self.session_widget.session.get_current_session_id()
                if session_id:
                    # Query database for run count
                    cursor = self.db_manager.get_connection().execute("""
                        SELECT total_runs FROM sessions WHERE session_id = ?
                    """, (session_id,))
                    row = cursor.fetchone()
                    if row:
                        self.lbl_run_count.setText(f"Runs: {row[0]}")
            except:
                pass
    
    # =========================================================================
    # Menu Actions
    # =========================================================================
    
    def _on_new_session(self):
        """Start new session."""
        # TODO: Implement
        QMessageBox.information(self, "New Session", "New session dialog (coming soon)")
    
    def _on_end_session(self):
        """End current session."""
        # TODO: Implement
        QMessageBox.information(self, "End Session", "End session (coming soon)")
    
    def _on_export_session(self):
        """Export session data."""
        # TODO: Implement
        QMessageBox.information(self, "Export", "Export session (coming soon)")
    
    def _on_uart_config(self):
        """Configure UART."""
        # TODO: Implement
        QMessageBox.information(self, "UART Config", "UART configuration dialog (coming soon)")
    
    def _on_i2c_config(self):
        """Configure I2C."""
        # TODO: Implement
        QMessageBox.information(self, "I2C Config", "I2C configuration dialog (coming soon)")
    
    def _on_debugger_config(self):
        """Configure debugger."""
        # TODO: Implement
        QMessageBox.information(self, "Debugger Config", "Debugger configuration dialog (coming soon)")
    
    def _on_gui_profile(self):
        """Manage GUI profile."""
        # TODO: Implement
        QMessageBox.information(self, "GUI Profile", "GUI profile settings (coming soon)")
    
    def _on_manage_profiles(self):
        """Manage test profiles."""
        # TODO: Implement
        QMessageBox.information(self, "Manage Profiles", "Test profile manager (coming soon)")
    
    def _on_new_profile(self):
        """Create new test profile."""
        # TODO: Implement
        QMessageBox.information(self, "New Profile", "Create test profile (coming soon)")
    
    def _on_vacuum_database(self):
        """Vacuum database."""
        reply = QMessageBox.question(
            self,
            "Vacuum Database",
            "Vacuum database to reclaim space?\n\nThis may take a few seconds.",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
        )
        
        if reply == QMessageBox.StandardButton.Yes:
            self.db_manager.vacuum()
            QMessageBox.information(self, "Success", "Database vacuumed successfully!")
    
    def _on_database_info(self):
        """Show database information."""
        size_bytes, percentage, status = self.db_manager.check_size()
        info = self.db_manager.get_table_info()
        
        msg = f"Database: {self.db_path}\n\n"
        msg += f"Size: {self.db_manager.format_size(size_bytes)} ({percentage:.1f}% of 2 GB)\n"
        msg += f"Status: {status}\n\n"
        msg += "Table Row Counts:\n"
        
        for table, count in info.items():
            msg += f"  {table}: {count}\n"
        
        QMessageBox.information(self, "Database Info", msg)
    
    def _on_cleanup_data(self):
        """Cleanup old data."""
        # TODO: Implement
        QMessageBox.information(self, "Cleanup", "Data cleanup dialog (coming soon)")
    
    def _on_about(self):
        """Show about dialog."""
        msg = "vzug-e-hinge Test & Control System\n\n"
        msg += "Version 1.0.0\n\n"
        msg += "Integrated test and control system for e-hinge devices.\n\n"
        msg += "Author: Kynsight\n"
        msg += "© 2025"
        
        QMessageBox.about(self, "About", msg)
    
    def _on_documentation(self):
        """Show documentation."""
        # TODO: Open documentation
        QMessageBox.information(self, "Documentation", "Documentation (coming soon)")
    
    def _on_tab_changed(self, index: int):
        """
        Handle tab change event.
        Refresh profiles when Session tab becomes active.
        
        Args:
            index: Index of newly selected tab
        """
        # Check if Session tab (index 0) is now active
        if index == 0 and hasattr(self, 'session_widget') and self.session_widget:
            self.session_widget.refresh_profiles()
    
    def closeEvent(self, event):
        """Handle application close."""
        reply = QMessageBox.question(
            self,
            "Exit",
            "Are you sure you want to exit?",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
        )
        
        if reply == QMessageBox.StandardButton.Yes:
            # Close database
            if self.db_manager:
                self.db_manager.close()
            event.accept()
        else:
            event.ignore()


def main():
    """Main entry point."""
    # Parse command line arguments
    db_path = "./database/ehinge.db"
    
    if len(sys.argv) > 1:
        db_path = sys.argv[1]
    
    # Create application
    app = QApplication(sys.argv)
    
    # Set application metadata
    app.setApplicationName("vzug-e-hinge")
    app.setOrganizationName("Kynsight")
    app.setOrganizationDomain("kynsight.com")
    
    # Create main window
    window = MainWindow(db_path)
    window.show()
    
    # Run application
    sys.exit(app.exec())


if __name__ == "__main__":
    main()
