"""Signals screen: DataTable of market signals with filter, refresh, and detail."""

import webbrowser
from datetime import date

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

from skilark_cli.client import SkilarkClient
from skilark_cli.display import format_relative_time, signal_source
from skilark_cli.tui.errors import friendly_error_message

_SIGNAL_ICONS: dict[str, str] = {
    "company_surge": "📈",
    "salary_insight": "💰",
    "company_layoff": "📉",
    "company_news": "📰",
    "sec_workforce_filing": "📋",
}


_NEWS_TYPE_LABELS: dict[str, str] = {
    "ai_disruption": "AI",
    "layoff": "Layoff",
    "controversy": "Controversy",
    "funding": "Funding",
    "acquisition": "M&A",
    "leadership": "Leadership",
    "product_launch": "Launch",
    "hiring_surge": "Hiring Surge",
    "talent": "Talent",
    "workplace": "Workplace",
    "hiring": "Hiring",
    "general": "General",
}


def _signal_icon(signal_type: str) -> str:
    return _SIGNAL_ICONS.get(signal_type, "📊")


class SignalsPane(Vertical):
    """Market signals table with detail panel."""

    BINDINGS = [
        Binding("slash", "start_filter", "/ Filter", show=True),
        Binding("r", "refresh", "Refresh", show=True),
        Binding("o", "open_link", "Open", show=True),
        Binding("escape", "clear_filter", "Close", show=False),
    ]

    def __init__(self, client: SkilarkClient | None = None, **kwargs) -> None:
        super().__init__(**kwargs)
        self.client = client
        self._signals: list[dict] = []
        self._week_of = ""
        self._filter_text = ""
        self._selected_index: int | None = None

    def compose(self) -> ComposeResult:
        yield Static("", id="signals-header")
        yield Input(
            placeholder="Type to filter...",
            id="filter-input",
            disabled=True,
        )
        yield DataTable(id="signals-table")
        yield Static("", id="signals-detail")

    def on_mount(self) -> None:
        filter_input = self.query_one("#filter-input", Input)
        filter_input.display = False

        table = self.query_one("#signals-table", DataTable)
        table.cursor_type = "row"
        table.add_columns("Type", "Time", "Subject", "Source")

        self._load_signals()

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

    def _on_data_loaded(self, data: dict) -> None:
        if not self.is_attached:
            return
        self._signals = data.get("signals", [])
        self._week_of = data.get("week_of", "")
        # Sort newest first by src_timestamp (fallback to metadata.published_at)
        self._signals.sort(key=self._signal_timestamp, reverse=True)
        self._render_table()

    @staticmethod
    def _signal_timestamp(signal: dict) -> str:
        """Extract the best available timestamp for sorting."""
        ts = signal.get("src_timestamp", "")
        if ts:
            return ts
        meta = signal.get("metadata", {})
        if isinstance(meta, dict):
            return meta.get("published_at", "")
        return ""

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

    def _render_table(self) -> None:
        header = self.query_one("#signals-header", Static)
        week_label = self._format_week(self._week_of)
        count = len(self._filtered_signals())
        total = len(self._signals)
        if self._filter_text:
            header.update(
                f"[bold]Market Signals[/bold] -- Week of {week_label}  "
                f"({count}/{total} shown)"
            )
        else:
            header.update(
                f"[bold]Market Signals[/bold] -- Week of {week_label}  "
                f"({total} signals)"
            )

        table = self.query_one("#signals-table", DataTable)
        table.clear()

        for signal in self._filtered_signals():
            signal_type = signal.get("type", signal.get("signal_type", ""))
            icon = _signal_icon(signal_type)
            title = signal.get("title", "")
            source = signal_source(signal)
            ts = signal.get("src_timestamp", "")
            if not ts:
                meta = signal.get("metadata", {})
                if isinstance(meta, dict):
                    ts = meta.get("published_at", "")
            table.add_row(f"{icon}", format_relative_time(ts), title, source)

        detail = self.query_one("#signals-detail", Static)
        detail.update("")
        self._selected_index = None

    def _filtered_signals(self) -> list[dict]:
        if not self._filter_text:
            return self._signals
        q = self._filter_text.lower()
        return [
            s
            for s in self._signals
            if q in s.get("title", "").lower()
            or q in s.get("body", "").lower()
            or q in s.get("type", s.get("signal_type", "")).lower()
        ]

    def on_data_table_row_highlighted(self, event: DataTable.RowHighlighted) -> None:
        if event.cursor_row is None:
            return
        filtered = self._filtered_signals()
        if 0 <= event.cursor_row < len(filtered):
            self._selected_index = event.cursor_row
            signal = filtered[event.cursor_row]
            self._show_detail(signal)

    def _show_detail(self, signal: dict) -> None:
        detail = self.query_one("#signals-detail", Static)
        title = signal.get("title", "")
        body = signal.get("body", "")
        signal_type = signal.get("type", signal.get("signal_type", ""))
        icon = _signal_icon(signal_type)
        meta = signal.get("metadata", {})
        if not isinstance(meta, dict):
            meta = {}

        lines = [f"\n{icon} [bold]{title}[/bold]"]

        if signal_type == "company_news":
            news_type = meta.get("news_type", "")
            label = _NEWS_TYPE_LABELS.get(news_type, news_type)
            source = signal_source(signal)
            pub = meta.get("published_at", "")
            url = meta.get("article_url", "")

            info_parts = []
            if label:
                info_parts.append(f"[bold cyan]{label}[/bold cyan]")
            if source:
                info_parts.append(f"via [italic]{source}[/italic]")
            if pub:
                info_parts.append(f"[dim]{format_relative_time(pub)}[/dim]")
            if info_parts:
                lines.append("  ".join(info_parts))

            if url:
                lines.append(f"[dim]Link: {url}[/dim]")
        elif signal_type in ("company_layoff", "sec_workforce_filing"):
            if body:
                lines.append(body)
            effective = meta.get("effective_date", "")
            if effective:
                lines.append(f"[bold red]Effective: {effective}[/bold red]")
            warn = meta.get("warn_date", "")
            if warn:
                lines.append(f"[dim]Filed: {warn}[/dim]")
        else:
            if body:
                lines.append(body)

        detail.update("\n".join(lines) + "\n")

    def action_start_filter(self) -> None:
        filter_input = self.query_one("#filter-input", Input)
        filter_input.disabled = False
        filter_input.display = True
        filter_input.focus()

    def action_clear_filter(self) -> None:
        filter_input = self.query_one("#filter-input", Input)
        filter_input.display = False
        filter_input.disabled = True
        filter_input.value = ""
        self._filter_text = ""
        self._render_table()
        self.query_one("#signals-table", DataTable).focus()

    def on_input_changed(self, event: Input.Changed) -> None:
        if event.input.id == "filter-input":
            self._filter_text = event.value
            self._render_table()

    def on_input_submitted(self, event: Input.Submitted) -> None:
        if event.input.id == "filter-input":
            filter_input = self.query_one("#filter-input", Input)
            filter_input.display = False
            filter_input.disabled = True
            self.query_one("#signals-table", DataTable).focus()

    def action_refresh(self) -> None:
        self._filter_text = ""
        filter_input = self.query_one("#filter-input", Input)
        filter_input.value = ""
        filter_input.display = False
        filter_input.disabled = True
        header = self.query_one("#signals-header", Static)
        header.update("[bold]Market Signals[/bold]\n\n[dim]Loading...[/dim]")
        self._load_signals()

    def action_open_link(self) -> None:
        if self._selected_index is None:
            return
        filtered = self._filtered_signals()
        if not (0 <= self._selected_index < len(filtered)):
            return
        signal = filtered[self._selected_index]
        meta = signal.get("metadata", {})
        if not isinstance(meta, dict):
            return
        url = meta.get("article_url", "")
        if url:
            webbrowser.open(url)

    @staticmethod
    def _format_week(week_of: str) -> str:
        if not week_of:
            return "unknown"
        try:
            d = date.fromisoformat(week_of)
            return f"{d.strftime('%b')} {d.day}"
        except (ValueError, TypeError):
            return week_of
