"""Timetable grid widget."""

from textual.app import ComposeResult
from textual.containers import Container, Grid
from textual.message import Message
from textual.widgets import Static
from textual.binding import Binding
from textual import events

from ..models import Timetable, Lesson, ChangeType, Day


class TimetableCell(Static):
    """A single cell in the timetable grid."""
    
    DEFAULT_CSS = """
    TimetableCell {
        width: 100%;
        height: 100%;
        content-align: center middle;
        text-align: center;
        padding: 0;
    }
    
    TimetableCell.empty {
        color: $text-muted;
    }
    
    TimetableCell.has-lesson {
        color: $text;
    }
    
    TimetableCell.has-change {
        background: #7a2020;
        color: white;
    }
    
    TimetableCell.cancelled {
        background: #7a2020;
        color: #ffaaaa;
        text-style: italic;
    }
    
    TimetableCell.day-off {
        background: #1a4a7a;
        color: #7ab8ff;
    }
    
    TimetableCell.selected {
        background: $primary;
        color: $text;
    }
    
    TimetableCell.header {
        color: $text-muted;
        text-style: bold;
    }
    
    TimetableCell.day-header {
        color: $text;
        text-style: bold;
        text-align: left;
        padding-left: 1;
    }
    """
    
    def __init__(
        self,
        content: str = "",
        day_index: int = -1,
        slot: int = -1,
        lesson: Lesson | None = None,
        is_header: bool = False,
        is_day_header: bool = False,
        is_day_off_cell: bool = False,
        **kwargs
    ) -> None:
        super().__init__(content, **kwargs)
        self.day_index = day_index
        self.slot = slot
        self.lesson = lesson
        self.is_header = is_header
        self.is_day_header = is_day_header
        self.is_day_off_cell = is_day_off_cell
        self._update_classes()
    
    def _update_classes(self) -> None:
        """Update CSS classes based on state."""
        self.remove_class("empty", "has-lesson", "has-change", "cancelled", "day-off", "header", "day-header")
        
        if self.is_header:
            self.add_class("header")
        elif self.is_day_header:
            self.add_class("day-header")
        elif self.is_day_off_cell:
            self.add_class("day-off")
        elif self.lesson:
            if self.lesson.is_day_off:
                self.add_class("day-off")
            elif self.lesson.change_type == ChangeType.CANCELLED:
                self.add_class("cancelled")
            elif self.lesson.has_change:
                self.add_class("has-change")
            elif not self.lesson.is_empty:
                self.add_class("has-lesson")
            else:
                self.add_class("empty")
        else:
            self.add_class("empty")


class TimetableGrid(Container):
    """
    Interactive timetable grid widget.
    
    Displays a grid layout with days as rows and lesson periods as columns.
    Uses actual grid layout for proper visual appearance.
    """
    
    can_focus = True  # Make the widget focusable
    
    BINDINGS = [
        Binding("up", "cursor_up", "Nahoru", show=False),
        Binding("down", "cursor_down", "Dolů", show=False),
        Binding("left", "cursor_left", "Vlevo", show=False),
        Binding("right", "cursor_right", "Vpravo", show=False),
    ]
    
    DEFAULT_CSS = """
    TimetableGrid {
        width: 100%;
        height: 1fr;
        padding: 0;
    }
    
    TimetableGrid:focus {
        border: solid $primary;
    }
    
    TimetableGrid > Grid {
        width: 100%;
        height: 100%;
        grid-gutter: 0;
    }
    """
    
    class CellSelected(Message):
        """Message sent when a cell is selected."""
        def __init__(self, day_index: int, slot: int, lesson: Lesson | None, is_day_off: bool = False, day_off_text: str = "") -> None:
            self.day_index = day_index
            self.slot = slot
            self.lesson = lesson
            self.is_day_off = is_day_off
            self.day_off_text = day_off_text
            super().__init__()
    
    def __init__(
        self,
        timetable: Timetable | None = None,
        id: str | None = None,
        classes: str | None = None,
    ) -> None:
        super().__init__(id=id, classes=classes)
        self._timetable = timetable
        self._cursor_day = 0
        self._cursor_slot = 0
        self._grid: Grid | None = None
        self._cells: dict[tuple[int, int], TimetableCell] = {}
        self._num_slots = 10
    
    @property
    def timetable(self) -> Timetable | None:
        return self._timetable
    
    @timetable.setter
    def timetable(self, value: Timetable | None) -> None:
        self._timetable = value
        self._cursor_day = 0
        self._cursor_slot = 0
        self.refresh_grid()
    
    def compose(self) -> ComposeResult:
        """Create child widgets."""
        # We'll build the grid dynamically
        yield Grid(id="timetable-inner-grid")
    
    def on_mount(self) -> None:
        """Set up the grid when mounted."""
        self._grid = self.query_one("#timetable-inner-grid", Grid)
        self.refresh_grid()
    
    def refresh_grid(self) -> None:
        """Refresh the entire grid."""
        if not self._grid:
            return
        
        # Clear existing cells
        self._grid.remove_children()
        self._cells.clear()
        
        if not self._timetable:
            return
        
        # Determine number of slots. Start with hours list, then check all lessons.
        self._num_slots = len(self._timetable.hours) if self._timetable.hours else 10
        for day in self._timetable.days:
            for lesson in day.lessons:
                if lesson.slot >= self._num_slots:
                    self._num_slots = lesson.slot + 1
        
        # Ensure at least 10 slots for visibility
        self._num_slots = max(self._num_slots, 10)
        
        # Set up grid columns: day label + slots
        self._grid.styles.grid_size_columns = self._num_slots + 1
        self._grid.styles.grid_size_rows = len(self._timetable.days) + 1
        
        # Header row with times
        self._add_header_row()
        
        # Data rows
        for day_idx, day in enumerate(self._timetable.days):
            self._add_day_row(day_idx, day)
        
        # Select first cell
        self._update_selection()
    
    def _add_header_row(self) -> None:
        """Add the header row with lesson times."""
        if not self._grid or not self._timetable:
            return
        
        # Empty corner cell
        corner = TimetableCell("", is_header=True)
        self._grid.mount(corner)
        
        # Time headers
        for slot in range(self._num_slots):
            hour = self._timetable.get_hour(slot)
            if hour:
                text = f"{hour.caption}\n{hour.start_time}"
            else:
                text = str(slot)
            
            cell = TimetableCell(text, is_header=True)
            self._grid.mount(cell)
    
    def _add_day_row(self, day_idx: int, day: Day) -> None:
        """Add a row for a day."""
        if not self._grid:
            return
        
        # Day label
        if day.date:
            day_text = f"{day.name}\n{day.date}"
        else:
            day_text = day.name
        
        day_cell = TimetableCell(day_text, is_day_header=True)
        
        # If whole day is off, mark the day header
        if day.is_day_off:
            day_cell.add_class("day-off")
        
        self._grid.mount(day_cell)
        
        # Lesson cells
        for slot in range(self._num_slots):
            lesson = day.get_lesson(slot)
            
            # Handle day-off: all cells get day-off styling with just "-"
            if day.is_day_off:
                cell = TimetableCell(
                    "-", 
                    day_index=day_idx, 
                    slot=slot, 
                    lesson=None,
                    is_day_off_cell=True
                )
                self._cells[(day_idx, slot)] = cell
                self._grid.mount(cell)
                continue
            
            # Regular lesson handling
            if lesson:
                if lesson.change_type == ChangeType.CANCELLED:
                    # Cancelled lessons: show abbreviation with strikethrough styling
                    text = lesson.display_short or "X"
                else:
                    text = lesson.display_short
                    if lesson.room and not lesson.is_day_off:
                        # Room in dimmer color using Rich markup
                        text += f"\n[dim]{lesson.room}[/dim]"
                cell = TimetableCell(text, day_index=day_idx, slot=slot, lesson=lesson)
            else:
                cell = TimetableCell("", day_index=day_idx, slot=slot, lesson=None)
            
            self._cells[(day_idx, slot)] = cell
            self._grid.mount(cell)
    
    def _update_selection(self) -> None:
        """Update visual selection."""
        for (d, s), cell in self._cells.items():
            if d == self._cursor_day and s == self._cursor_slot:
                cell.add_class("selected")
            else:
                cell.remove_class("selected")
        
        # Post message
        lesson = None
        is_day_off = False
        day_off_text = ""
        if self._timetable and 0 <= self._cursor_day < len(self._timetable.days):
            day = self._timetable.days[self._cursor_day]
            lesson = day.get_lesson(self._cursor_slot)
            is_day_off = day.is_day_off
            day_off_text = day.day_off_text
        self.post_message(self.CellSelected(self._cursor_day, self._cursor_slot, lesson, is_day_off, day_off_text))
    
    def action_cursor_up(self) -> None:
        """Move cursor up."""
        if self._timetable and self._cursor_day > 0:
            self._cursor_day -= 1
            self._update_selection()
    
    def action_cursor_down(self) -> None:
        """Move cursor down."""
        if self._timetable and self._cursor_day < len(self._timetable.days) - 1:
            self._cursor_day += 1
            self._update_selection()
    
    def action_cursor_left(self) -> None:
        """Move cursor left."""
        if self._cursor_slot > 0:
            self._cursor_slot -= 1
            self._update_selection()
    
    def action_cursor_right(self) -> None:
        """Move cursor right."""
        if self._cursor_slot < self._num_slots - 1:
            self._cursor_slot += 1
            self._update_selection()
    
    def on_click(self, event: events.Click) -> None:
        """Handle click on grid to select cell."""
        # Focus this widget on click
        self.focus()
        
        # Find clicked cell
        for (d, s), cell in self._cells.items():
            if cell.region.contains(event.x, event.y):
                self._cursor_day = d
                self._cursor_slot = s
                self._update_selection()
                break
    
    def on_focus(self, event: events.Focus) -> None:
        """Handle focus event."""
        self._update_selection()
