"""Modules List Widget for displaying module state table."""

from datetime import datetime
from typing import Any, List, Optional

from textual.app import ComposeResult
from textual.widgets import DataTable, Static

from xp.models.term.module_state import ModuleState
from xp.services.term.state_monitor_service import StateMonitorService


class ModulesListWidget(Static):
    """Widget displaying module states in a data table.

    Shows module information with real-time updates from StateMonitorService.
    Table displays: name, serial_number, module_type, outputs, report, status, last_update.

    Attributes:
        service: StateMonitorService for module state updates.
        table: DataTable widget displaying module information.
    """

    def __init__(
        self,
        service: Optional[StateMonitorService] = None,
        *args: Any,
        **kwargs: Any,
    ) -> None:
        """Initialize the Modules List widget.

        Args:
            service: Optional StateMonitorService for signal subscriptions.
            args: Additional positional arguments for Static.
            kwargs: Additional keyword arguments for Static.
        """
        super().__init__(*args, **kwargs)
        self.service = service
        self.table: Optional[DataTable] = None
        self._row_keys: dict[str, Any] = {}  # Map serial_number to row key

    def compose(self) -> ComposeResult:
        """Compose the widget layout.

        Yields:
            DataTable widget.
        """
        self.table = DataTable(id="modules-table", cursor_type="row")
        yield self.table

    def on_mount(self) -> None:
        """Initialize table and subscribe to service signals when widget mounts."""
        # Set border title
        self.border_title = "Modules"

        if self.table:
            # Set table to full width
            self.table.styles.width = "100%"

            # Setup table columns
            self.table.add_column("name", key="name")
            self.table.add_column("serial number", key="serial_number")
            self.table.add_column("module type", key="module_type")
            self.table.add_column("outputs", key="outputs")
            self.table.add_column("report", key="report")
            self.table.add_column("status", key="status")
            self.table.add_column("last update", key="last_update")

        if self.service:
            self.service.on_module_list_updated.connect(self.update_module_list)
            self.service.on_module_state_changed.connect(self.update_module_state)

    def on_unmount(self) -> None:
        """Unsubscribe from service signals when widget unmounts."""
        if self.service:
            self.service.on_module_list_updated.disconnect(self.update_module_list)
            self.service.on_module_state_changed.disconnect(self.update_module_state)

    def update_module_list(self, module_states: List[ModuleState]) -> None:
        """Update entire module list from service.

        Clears existing table and repopulates with all modules.

        Args:
            module_states: List of all module states.
        """
        if not self.table:
            return

        # Clear existing rows
        self.table.clear()
        self._row_keys.clear()

        # Add all modules
        for module_state in module_states:
            self._add_module_row(module_state)

    def update_module_state(self, module_state: ModuleState) -> None:
        """Update individual module state in table.

        Updates existing row if module exists, otherwise adds new row.

        Args:
            module_state: Updated module state.
        """
        if not self.table:
            return

        serial_number = module_state.serial_number

        if serial_number in self._row_keys:
            # Update existing row
            row_key = self._row_keys[serial_number]
            self.table.update_cell(
                row_key, "outputs", self._format_outputs(module_state.outputs)
            )
            self.table.update_cell(
                row_key, "report", self._format_report(module_state.auto_report)
            )
            self.table.update_cell(row_key, "status", module_state.error_status)
            self.table.update_cell(
                row_key,
                "last_update",
                self._format_last_update(module_state.last_update),
            )
        else:
            # Add new row
            self._add_module_row(module_state)

    def _add_module_row(self, module_state: ModuleState) -> None:
        """Add a module row to the table.

        Args:
            module_state: Module state to add.
        """
        if not self.table:
            return

        row_key = self.table.add_row(
            module_state.name,
            module_state.serial_number,
            module_state.module_type,
            self._format_outputs(module_state.outputs),
            self._format_report(module_state.auto_report),
            module_state.error_status,
            self._format_last_update(module_state.last_update),
        )
        self._row_keys[module_state.serial_number] = row_key

    def _format_outputs(self, outputs: str) -> str:
        """Format outputs for display.

        Args:
            outputs: Raw output string.

        Returns:
            Formatted output string (empty string for modules without outputs).
        """
        return outputs

    def _format_report(self, auto_report: bool) -> str:
        """Format auto-report status for display.

        Args:
            auto_report: Auto-report boolean value.

        Returns:
            "Y" if True, "N" if False.
        """
        return "Y" if auto_report else "N"

    def _format_last_update(self, last_update: Optional[datetime]) -> str:
        """Format last update timestamp for display.

        Shows elapsed time in HH:MM:SS format or "--:--:--" if never updated.

        Args:
            last_update: Last update timestamp or None.

        Returns:
            Formatted time string.
        """
        if last_update is None:
            return "--:--:--"

        # Calculate elapsed time
        elapsed = datetime.now() - last_update
        total_seconds = int(elapsed.total_seconds())

        hours = total_seconds // 3600
        minutes = (total_seconds % 3600) // 60
        seconds = total_seconds % 60

        return f"{hours:02d}:{minutes:02d}:{seconds:02d}"

    def refresh_last_update_times(self) -> None:
        """Refresh only the last_update column for all modules.

        Updates the elapsed time display without querying the service.
        """
        if not self.table or not self.service:
            return

        # Update last_update column for each module
        for serial_number, row_key in self._row_keys.items():
            # Get the module state from service
            module_states = self.service.module_states
            module_state = next(
                (m for m in module_states if m.serial_number == serial_number), None
            )
            if module_state:
                # Update only the last_update cell
                self.table.update_cell(
                    row_key,
                    "last_update",
                    self._format_last_update(module_state.last_update),
                )
