"""Main Bakalari TUI application."""

from textual.app import App, ComposeResult
from textual.binding import Binding
from textual.containers import Container, Vertical, Horizontal
from textual.screen import Screen
from textual.widgets import Footer, Header, Static, LoadingIndicator

from .models import Timetable, TimetableType
from .parser import fetch_timetable, FetchError, ParseError
from .config import Config, extract_groups_from_timetable, filter_lessons_by_groups
from .widgets.onboarding import OnboardingScreen
from .widgets.timetable import TimetableGrid
from .widgets.detail import DetailPanel
from .widgets.groups import GroupSelectionScreen


class TimetableScreen(Screen):
    """Main timetable display screen."""
    
    BINDINGS = [
        Binding("q", "quit", "Ukončit"),
        Binding("r", "refresh", "Obnovit"),
        Binding("c", "change_url", "Změnit URL"),
        Binding("g", "select_groups", "Skupiny"),
        Binding("shift+left", "prev_week", "Předchozí", show=True),
        Binding("shift+right", "next_week", "Další", show=True),
        Binding("escape", "back", "Zpět"),
    ]
    
    DEFAULT_CSS = """
    TimetableScreen {
        layout: vertical;
    }
    
    TimetableScreen #main-container {
        height: 1fr;
    }
    
    TimetableScreen #status-bar {
        height: 1;
        dock: top;
        background: $primary;
        color: $text;
        padding: 0 1;
    }
    
    TimetableScreen #loading {
        align: center middle;
        height: 100%;
    }
    
    TimetableScreen #error-display {
        align: center middle;
        height: 100%;
        color: $error;
    }
    
    TimetableScreen TimetableGrid {
        height: 1fr;
    }
    
    TimetableScreen DetailPanel {
        dock: bottom;
    }
    """
    
    def __init__(self, url: str, config: Config, name: str | None = None) -> None:
        super().__init__(name=name)
        self._url = url
        self._config = config
        self._timetable: Timetable | None = None
        self._loading = False
        self._error: str | None = None
    
    def compose(self) -> ComposeResult:
        """Create child widgets."""
        yield Header()
        yield Static("Načítání...", id="status-bar")
        
        with Container(id="main-container"):
            yield LoadingIndicator(id="loading")
            yield Static("", id="error-display")
            yield TimetableGrid(id="timetable-grid")
            yield DetailPanel(id="detail-panel")
        
        yield Footer()
    
    def on_mount(self) -> None:
        """Load timetable when screen is mounted."""
        self._show_loading()
        self.load_timetable(self._url)
    
    def _show_loading(self) -> None:
        """Show loading state."""
        self._loading = True
        self.query_one("#loading").display = True
        self.query_one("#error-display").display = False
        self.query_one("#timetable-grid").display = False
        self.query_one("#detail-panel").display = False
    
    def _show_error(self, message: str) -> None:
        """Show error state."""
        self._loading = False
        self._error = message
        self.query_one("#loading").display = False
        error_display = self.query_one("#error-display", Static)
        error_display.update(f"Chyba: {message}")
        error_display.display = True
        self.query_one("#timetable-grid").display = False
        self.query_one("#detail-panel").display = False
    
    def _show_timetable(self) -> None:
        """Show timetable state."""
        self._loading = False
        self._error = None
        self.query_one("#loading").display = False
        self.query_one("#error-display").display = False
        self.query_one("#timetable-grid").display = True
        self.query_one("#detail-panel").display = True
        
        # Update status bar
        if self._timetable:
            status = f"{self._timetable.type_display} | {self._timetable.entity_type}: {self._timetable.entity_id}"
            # Show group filter status
            if self._config.selected_groups:
                status += f" | Skupiny: {', '.join(self._config.selected_groups)}"
            self.query_one("#status-bar", Static).update(status)
    
    def load_timetable(self, url: str) -> None:
        """Load timetable from URL."""
        self._url = url
        self.run_worker(self._fetch_timetable_async(url), exclusive=True)
    
    async def _fetch_timetable_async(self, url: str) -> None:
        """Async worker to fetch timetable."""
        try:
            # Run blocking I/O in thread
            timetable = await self.app.run_async_in_thread(
                lambda: fetch_timetable(url)
            )
            self._timetable = timetable
            
            # Apply group filtering
            self._apply_group_filter()
            
            # Update grid
            grid = self.query_one("#timetable-grid", TimetableGrid)
            grid.timetable = timetable
            
            # Update detail panel with timetable for time lookups
            detail = self.query_one("#detail-panel", DetailPanel)
            detail.set_timetable(timetable)
            
            self._show_timetable()
            
            # Focus the grid
            grid.focus()
            
        except (FetchError, ParseError) as e:
            self._show_error(str(e))
        except Exception as e:
            self._show_error(f"Neočekávaná chyba: {e}")
    
    def _apply_group_filter(self) -> None:
        """Apply group filtering to timetable lessons."""
        if not self._timetable or not self._config.selected_groups:
            return
        
        for day in self._timetable.days:
            day.lessons = filter_lessons_by_groups(day.lessons, self._config.selected_groups)
    
    def on_timetable_grid_cell_selected(self, event: TimetableGrid.CellSelected) -> None:
        """Handle cell selection in timetable grid."""
        detail_panel = self.query_one("#detail-panel", DetailPanel)
        
        day_name = ""
        day_date = ""
        
        if self._timetable and 0 <= event.day_index < len(self._timetable.days):
            day = self._timetable.days[event.day_index]
            day_name = day.name
            day_date = day.date
        
        detail_panel.update_lesson(event.lesson, day_name, day_date, event.is_day_off, event.day_off_text)
    
    def action_refresh(self) -> None:
        """Refresh current timetable."""
        self._show_loading()
        self.load_timetable(self._url)
    
    def action_prev_week(self) -> None:
        """Switch to previous week type."""
        if not self._timetable:
            return
        
        current = self._timetable.timetable_type
        
        # Cycle: Next -> Actual -> Permanent
        if current == TimetableType.NEXT:
            new_type = TimetableType.ACTUAL
        elif current == TimetableType.ACTUAL:
            new_type = TimetableType.PERMANENT
        else:
            # Already at permanent, can't go back
            return
        
        new_url = self._timetable.get_url(new_type)
        self._show_loading()
        self.load_timetable(new_url)
    
    def action_next_week(self) -> None:
        """Switch to next week type."""
        if not self._timetable:
            return
        
        current = self._timetable.timetable_type
        
        # Cycle: Permanent -> Actual -> Next
        if current == TimetableType.PERMANENT:
            new_type = TimetableType.ACTUAL
        elif current == TimetableType.ACTUAL:
            new_type = TimetableType.NEXT
        else:
            # Already at next, can't go forward
            return
        
        new_url = self._timetable.get_url(new_type)
        self._show_loading()
        self.load_timetable(new_url)
    
    def action_back(self) -> None:
        """Go back to onboarding."""
        self.app.pop_screen()
    
    def action_change_url(self) -> None:
        """Change timetable URL - go back to onboarding."""
        self._config.clear()
        self.app.switch_screen(OnboardingScreen())
    
    def action_select_groups(self) -> None:
        """Open group selection screen."""
        if not self._timetable:
            return
        
        # Re-fetch to get all groups (not filtered)
        self.app.push_screen(
            GroupSelectionScreen(
                available_groups=extract_groups_from_timetable(self._timetable),
                selected_groups=self._config.selected_groups,
            )
        )
    
    def action_quit(self) -> None:
        """Quit the application."""
        self.app.exit()


class BakalariApp(App):
    """Main Bakalari TUI application."""
    
    TITLE = "bakalari-cli"
    CSS = """
    Screen {
        background: $background;
    }
    """
    
    BINDINGS = [
        Binding("q", "quit", "Ukončit", show=True),
        Binding("ctrl+c", "quit", "Ukončit", show=False),
    ]
    
    def __init__(self) -> None:
        super().__init__()
        self._config = Config.load()
        self._pending_timetable: Timetable | None = None
    
    def on_mount(self) -> None:
        """Show appropriate screen on startup."""
        if self._config.has_url:
            # Auto-load saved timetable
            self.push_screen(TimetableScreen(self._config.url, self._config))
        else:
            # Show onboarding
            self.push_screen(OnboardingScreen())
    
    def on_onboarding_screen_url_submitted(self, event: OnboardingScreen.UrlSubmitted) -> None:
        """Handle URL submission from onboarding."""
        # Save URL to config
        self._config.url = event.url
        self._config.save()
        
        # Fetch timetable to check for groups
        self._check_groups_and_show_timetable(event.url)
    
    def _check_groups_and_show_timetable(self, url: str) -> None:
        """Check if timetable has groups and potentially show selection."""
        self.run_worker(self._fetch_and_check_groups(url), exclusive=True)
    
    async def _fetch_and_check_groups(self, url: str) -> None:
        """Fetch timetable and check for groups."""
        try:
            timetable = await self.run_async_in_thread(
                lambda: fetch_timetable(url)
            )
            
            groups = extract_groups_from_timetable(timetable)
            
            if groups and not self._config.selected_groups:
                # Show group selection screen
                self._pending_timetable = timetable
                self.push_screen(
                    GroupSelectionScreen(
                        available_groups=groups,
                        selected_groups=[],
                    )
                )
            else:
                # No groups or already selected, go straight to timetable
                self.push_screen(TimetableScreen(url, self._config))
                
        except Exception:
            # On error, just show timetable screen (it will handle errors)
            self.push_screen(TimetableScreen(url, self._config))
    
    def on_group_selection_screen_groups_selected(self, event: GroupSelectionScreen.GroupsSelected) -> None:
        """Handle group selection."""
        self._config.selected_groups = event.groups
        self._config.save()
        
        # Pop group selection screen
        self.pop_screen()
        
        # If we came from onboarding, also pop that and show timetable
        if self._pending_timetable:
            self.pop_screen()  # Pop onboarding
            self.push_screen(TimetableScreen(self._config.url, self._config))
            self._pending_timetable = None
        else:
            # Came from timetable, refresh it
            pass  # The timetable screen will refresh automatically
    
    def on_group_selection_screen_skipped(self, event: GroupSelectionScreen.Skipped) -> None:
        """Handle group selection skip."""
        self._config.selected_groups = []
        self._config.save()
        
        # Pop group selection screen
        self.pop_screen()
        
        # If we came from onboarding, also pop that and show timetable
        if self._pending_timetable:
            self.pop_screen()  # Pop onboarding
            self.push_screen(TimetableScreen(self._config.url, self._config))
            self._pending_timetable = None
    
    async def run_async_in_thread(self, func):
        """Run a blocking function in a thread."""
        import asyncio
        loop = asyncio.get_event_loop()
        return await loop.run_in_executor(None, func)


def main() -> None:
    """Main entry point."""
    app = BakalariApp()
    app.run()


if __name__ == "__main__":
    main()
