#!/usr/bin/env python3
# This software is distributed under the terms of the MIT License.
# Copyright (c) 2025 Dmitry Ponomarev.
# Author: Dmitry Ponomarev <ponomarevda96@gmail.com>
"""
Tsugite - A system-oriented dashboard for Cyphal (CAN + UDP) & DroneCAN (from YAML)
that renders live panels from a YAML manifest—so you watch the system, not just the bus.
"""

import sys
import logging
import argparse
from pathlib import Path

import yaml
from PySide6.QtWidgets import (
    QApplication,
    QMainWindow,
    QPushButton,
    QVBoxLayout,
    QHBoxLayout,
    QWidget,
    QStackedWidget,
    QSizePolicy,
)
from PySide6.QtCore import Qt, QTimer

from tsugite.backend.backend import BaseBackend
from tsugite.ui.desktop.widgets import WidgetFactory, TableWidget

logger = logging.getLogger(__name__)

class MainWindow(QMainWindow):
    def __init__(self, config: dict, communicator: object):
        super().__init__()
        self.config = config
        self.communicator = communicator

        self.setWindowTitle(self.config.get("metadata", {}).get("project", " "))
        self.resize(600, 400)
        main_layout = QVBoxLayout()

        # Navigation Bar between Panels
        self.nav_bar_buttons = []
        nav_bar = QHBoxLayout()
        for idx, (panel_name, panel_info) in enumerate(self.config["panels"].items()):
            btn = QPushButton(panel_name)
            btn.setCheckable(True)
            btn.clicked.connect(lambda checked, i=idx: self.switch_panel(i))
            self.nav_bar_buttons.append(btn)
            nav_bar.addWidget(btn)
        if self.nav_bar_buttons:
            self.nav_bar_buttons[0].setChecked(True)
        main_layout.addLayout(nav_bar)

        # Stack of Panels
        self.stack = QStackedWidget()
        for idx, (panel_name, panel_info) in enumerate(self.config["panels"].items()):
            self.stack.addWidget(self.create_panel(panel_info))
        main_layout.addWidget(self.stack)

        container = QWidget()
        container.setLayout(main_layout)
        self.setCentralWidget(container)

    def create_panel(self, panel_info: dict) -> QWidget:
        """Dynamically create a QWidget based on panel definition."""
        panel = QWidget()
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(2)
        layout.setAlignment(Qt.AlignTop)

        for widget_cfg in panel_info.get("widgets", []):
            widget_cfg["communicator"] = self.communicator # HACK: pass communicator to widgets
            widget = WidgetFactory.create(widget_cfg)
            if isinstance(widget, TableWidget):
                widget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
            layout.addWidget(widget)

        panel.setLayout(layout)
        return panel

    def switch_panel(self, index: int):
        """Switch visible panel by index."""
        for i, btn in enumerate(self.nav_bar_buttons):
            btn.setChecked(i == index)
        self.stack.setCurrentIndex(index)


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument(
        "--config",
        type=Path,
        default=Path("configs/examples/drilling.yaml"),
        help="Path to YAML configuration file (default: configs/examples/drilling.yaml)",
    )
    parser.add_argument(
        "--backend",
        type=str,
        default="dummy",
        help="Communicator backend to use (default: dummy)",
    )
    parser.add_argument(
        "-v", "--verbose", action="store_true", help="Enable verbose logging"
    )
    args = parser.parse_args()

    logging_level = logging.DEBUG if args.verbose else logging.WARNING
    logging.basicConfig(
        level=logging_level,
        format="[%(asctime)s] [%(levelname)s] %(message)s",
        datefmt="%H:%M:%S",
    )
    logger.setLevel(logging_level)
    logging.getLogger("dronecan").setLevel(logging_level)

    if not args.config.exists():
        logger.critical("YAML config not found: %s", args.config)
        sys.exit(1)

    try:
        with open(args.config, "r", encoding="utf-8") as f:
            config = yaml.safe_load(f) or {}
    except Exception as e:
        logging.error(f"Failed to load YAML: {e}")
        sys.exit(1)

    app = QApplication(sys.argv)
    if args.backend == "dummy":
        from tsugite.backend.dummy_backend import DummyBackend
        communicator = DummyBackend()
    elif args.backend == "dronecan":
        from tsugite.backend.dronecan_backend import DronecanBackend
        communicator = DronecanBackend()
    window = MainWindow(config, communicator)
    window.show()

    TICK_HZ = 100
    timer = QTimer()
    timer.timeout.connect(lambda: communicator.tick(1.0 / TICK_HZ))
    timer.start(int(1000 / TICK_HZ))  # milliseconds per tick

    sys.exit(app.exec())


if __name__ == "__main__":
    main()
