"""Watches pane: DataTable of user watches with alert drill-down navigation."""

import webbrowser

import time

from textual import work
from textual.app import ComposeResult
from textual.binding import Binding
from textual.containers import Vertical
from textual.widgets import DataTable, Static

from skilark_cli.tui.errors import friendly_error_message


class WatchesPane(Vertical):
    """Watches table with alert drill-down."""

    BINDINGS = [
        Binding("n", "new_watch", "New", show=True),
        Binding("p", "toggle_pause", "Pause/Resume", show=True),
        Binding("d", "delete_watch", "Delete", show=True),
        Binding("r", "refresh", "Refresh", show=True),
        Binding("b", "back", "Back", show=False),
        Binding("o", "open_link", "Open", show=False),
        Binding("escape", "back", "Back", show=False),
    ]

    def on_data_table_row_selected(self, event: DataTable.RowSelected) -> None:
        """Handle Enter/click on a table row."""
        self.action_select()

    def __init__(self, client=None, **kwargs) -> None:
        super().__init__(**kwargs)
        self.client = client
        self._watches: list[dict] = []
        self._alerts: list[dict] = []
        self._selected_watch: dict | None = None
        self._view: str = "watches"
        self._delete_pressed_at: float = 0.0
        self._delete_timeout: float = 2.0

    def compose(self) -> ComposeResult:
        yield Static("", id="watches-header")
        yield DataTable(id="watches-table")
        yield DataTable(id="alerts-table")

    def on_mount(self) -> None:
        watches_table = self.query_one("#watches-table", DataTable)
        watches_table.cursor_type = "row"
        watches_table.add_columns("Label", "Filters", "Status", "Alerts")

        alerts_table = self.query_one("#alerts-table", DataTable)
        alerts_table.cursor_type = "row"
        alerts_table.add_columns("Title", "Company", "Location", "Date")
        alerts_table.display = False

        self._load_watches()

    def activate(self) -> None:
        """Called when tab becomes active."""
        self._load_watches()
        self._update_footer_bindings()

    # ------------------------------------------------------------------
    # Data loading
    # ------------------------------------------------------------------

    @work(thread=True, exit_on_error=False)
    def _load_watches(self) -> None:
        if not self.client:
            self.app.call_from_thread(
                self._render_empty, "No API client configured."
            )
            return
        try:
            data = self.client.list_watches()
        except Exception as e:
            self.app.call_from_thread(
                self._render_empty, friendly_error_message(e)
            )
            return
        self.app.call_from_thread(self._on_watches_loaded, data)

    def _on_watches_loaded(self, watches: list[dict]) -> None:
        if not self.is_attached:
            return
        self._watches = watches
        self._render_watches_table()

    @work(thread=True, exit_on_error=False)
    def _load_alerts(self, watch_id: str) -> None:
        try:
            data = self.client.get_watch_alerts(watch_id)
        except Exception as e:
            self.app.call_from_thread(
                self._render_empty, friendly_error_message(e)
            )
            return
        self.app.call_from_thread(self._on_alerts_loaded, data)

    def _on_alerts_loaded(self, data: dict) -> None:
        if not self.is_attached:
            return
        self._alerts = data.get("alerts", [])
        self._render_alerts_table()
        self._show_alerts_view()

    # ------------------------------------------------------------------
    # Rendering
    # ------------------------------------------------------------------

    def _render_empty(self, message: str) -> None:
        if not self.is_attached:
            return
        header = self.query_one("#watches-header", Static)
        header.update(f"[bold]Watches[/bold]\n\n[dim]{message}[/dim]")

    def _render_watches_table(self) -> None:
        header = self.query_one("#watches-header", Static)
        if not self._watches:
            header.update(
                "[bold]Watches[/bold]\n\n"
                "[dim]No watches yet. Press [bold]n[/bold] to create one.[/dim]"
            )
        else:
            count = len(self._watches)
            header.update(
                f"[bold]Watches[/bold]  ({count} watch{'es' if count != 1 else ''})"
            )

        table = self.query_one("#watches-table", DataTable)
        table.clear()
        for watch in self._watches:
            label = watch.get("label", "")
            filters = self._filter_summary(watch)
            status = "Active" if watch.get("is_active", True) else "Paused"
            alert_count = str(watch.get("pending_alerts", 0))
            table.add_row(label, filters, status, alert_count)

    def _render_alerts_table(self) -> None:
        header = self.query_one("#watches-header", Static)
        watch_label = (
            self._selected_watch.get("label", "")
            if self._selected_watch
            else ""
        )
        count = len(self._alerts)
        if not self._alerts:
            header.update(
                f"[bold]{watch_label} -- Alerts[/bold]\n\n"
                "[dim]No alerts yet.[/dim]"
            )
        else:
            header.update(
                f"[bold]{watch_label} -- Alerts[/bold]  ({count} alert{'s' if count != 1 else ''})"
            )

        table = self.query_one("#alerts-table", DataTable)
        table.clear()
        for alert in self._alerts:
            title = alert.get("listing_title", "")
            company = alert.get("listing_company", "")
            location = alert.get("listing_location", "") or "-"
            created = alert.get("created_at", "")[:10]
            table.add_row(title, company, location, created)

    _ROLE_LABELS: dict[str, str] = {
        "ai_ml": "AI/ML", "data_eng": "Data Eng", "swe": "SWE",
        "platform": "Platform", "devops": "DevOps", "security": "Security",
        "product": "Product", "design": "Design", "other": "Other",
    }

    @staticmethod
    def _filter_summary(watch: dict) -> str:
        """Build compact filter string from watch filters."""
        parts: list[str] = []
        query = watch.get("query")
        if query:
            # Truncate long queries for the table cell.
            display = query if len(query) <= 40 else query[:37] + "..."
            parts.append(display)
        else:
            # Legacy watches without query — show skills/role_category.
            skills = watch.get("skills")
            if skills:
                parts.append(", ".join(skills))
            role_category = watch.get("role_category", "")
            if role_category:
                parts.append(WatchesPane._ROLE_LABELS.get(role_category, role_category))
        seniority = watch.get("seniority", "")
        if seniority:
            parts.append(seniority)
        company_slug = watch.get("company_slug", "")
        if company_slug:
            parts.append(company_slug)
        location = watch.get("location", "")
        if location:
            parts.append(location)
        return " / ".join(parts) if parts else "-"

    # ------------------------------------------------------------------
    # View switching
    # ------------------------------------------------------------------

    def _show_watches_view(self) -> None:
        self._view = "watches"
        self.query_one("#watches-table", DataTable).display = True
        self.query_one("#alerts-table", DataTable).display = False
        self._render_watches_table()
        self._update_footer_bindings()

    def _show_alerts_view(self) -> None:
        self._view = "alerts"
        self.query_one("#watches-table", DataTable).display = False
        self.query_one("#alerts-table", DataTable).display = True
        self._update_footer_bindings()

    def _update_footer_bindings(self) -> None:
        """Push view-aware bindings to the footer."""
        from skilark_cli.tui.app import FooterBar

        try:
            footer = self.app.query_one(FooterBar)
        except Exception:
            return

        if self._view == "watches":
            bindings = [
                Binding("n", "new_watch", "New", show=True),
                Binding("p", "toggle_pause", "Pause/Resume", show=True),
                Binding("d", "delete_watch", "Delete", show=True),
                Binding("r", "refresh", "Refresh", show=True),
            ]
        else:
            bindings = [
                Binding("b", "back", "Back", show=True),
                Binding("o", "open_link", "Open", show=True),
            ]
        footer.set_context_bindings(bindings)

    # ------------------------------------------------------------------
    # Selected row helpers
    # ------------------------------------------------------------------

    def _selected_watch_from_table(self) -> dict | None:
        """Return the watch dict for the currently highlighted row, or None."""
        table = self.query_one("#watches-table", DataTable)
        if table.cursor_row is None or not self._watches:
            return None
        idx = table.cursor_row
        if 0 <= idx < len(self._watches):
            return self._watches[idx]
        return None

    def _selected_alert_from_table(self) -> dict | None:
        """Return the alert dict for the currently highlighted row, or None."""
        table = self.query_one("#alerts-table", DataTable)
        if table.cursor_row is None or not self._alerts:
            return None
        idx = table.cursor_row
        if 0 <= idx < len(self._alerts):
            return self._alerts[idx]
        return None

    # ------------------------------------------------------------------
    # Actions
    # ------------------------------------------------------------------

    def action_new_watch(self) -> None:
        """Push the WatchCreateModal (lazy import -- it may not exist yet)."""
        try:
            from skilark_cli.tui.screens.watch_create_modal import (
                WatchCreateModal,
            )
        except ImportError:
            header = self.query_one("#watches-header", Static)
            header.update(
                "[bold]Watches[/bold]\n\n"
                "[dim]Watch creation is not available yet.[/dim]"
            )
            return

        def _on_dismiss(result: bool | None) -> None:
            if result:
                self._load_watches()

        self.app.push_screen(WatchCreateModal(client=self.client), _on_dismiss)

    def action_select(self) -> None:
        """Enter drills into alerts for the selected watch, or opens link in alerts view."""
        if self._view == "watches":
            watch = self._selected_watch_from_table()
            if watch is None:
                return
            self._selected_watch = watch
            self._load_alerts(watch["id"])
        elif self._view == "alerts":
            self.action_open_link()

    def action_toggle_pause(self) -> None:
        """Toggle is_active on the selected watch."""
        if self._view != "watches":
            return
        watch = self._selected_watch_from_table()
        if watch is None:
            return
        new_active = not watch.get("is_active", True)
        self._toggle_pause_worker(watch["id"], new_active)

    @work(thread=True, exit_on_error=False)
    def _toggle_pause_worker(self, watch_id: str, is_active: bool) -> None:
        try:
            self.client.update_watch(watch_id, is_active=is_active)
        except Exception as e:
            self.app.call_from_thread(
                self._render_empty, friendly_error_message(e)
            )
            return
        self.app.call_from_thread(self._load_watches)

    def action_delete_watch(self) -> None:
        """Delete the selected watch (press d twice to confirm)."""
        if self._view != "watches":
            return
        watch = self._selected_watch_from_table()
        if watch is None:
            return
        now = time.monotonic()
        if now - self._delete_pressed_at <= self._delete_timeout:
            self._delete_pressed_at = 0.0
            self._delete_watch_worker(watch["id"])
        else:
            self._delete_pressed_at = now
            header = self.query_one("#watches-header", Static)
            header.update(
                "[bold]Watches[/bold]\n\n"
                "[bold reverse] Press d again to delete [/bold reverse]"
            )

    @work(thread=True, exit_on_error=False)
    def _delete_watch_worker(self, watch_id: str) -> None:
        try:
            self.client.delete_watch(watch_id)
        except Exception as e:
            self.app.call_from_thread(
                self._render_empty, friendly_error_message(e)
            )
            return
        self.app.call_from_thread(self._load_watches)

    def action_refresh(self) -> None:
        """Reload watches."""
        header = self.query_one("#watches-header", Static)
        header.update("[bold]Watches[/bold]\n\n[dim]Loading...[/dim]")
        self._load_watches()

    def action_back(self) -> None:
        """Return from alerts to watches view."""
        if self._view == "alerts":
            self._show_watches_view()

    def action_open_link(self) -> None:
        """Open the selected alert's listing URL in the browser."""
        if self._view != "alerts":
            return
        alert = self._selected_alert_from_table()
        if alert is None:
            return
        url = alert.get("listing_url", "")
        if url:
            webbrowser.open(url)
