import os

from rich.syntax import Syntax
from textual.app import ComposeResult
from textual.containers import Horizontal
from textual.widget import Widget
from textual.widgets import Label, Static, TextArea

from bibtui.bib.models import BibEntry
from bibtui.bib.parser import entry_to_bibtex_str
from bibtui.pdf.paths import parse_jabref_path


def _render_entry(entry: BibEntry, colors: dict[str, str]) -> str:
    """Build a Rich-formatted string for the main body of the detail pane.

    *colors* is a dict with keys: title, key, required, optional, tag_fg,
    tag_bg, warning.  Values are Rich-compatible color strings (hex or names).
    """
    c = colors
    lines: list[str] = []

    # Title
    lines.append(f"[bold {c['title']}]{entry.title or '(no title)'}[/]")
    lines.append("")

    # Entry type badge
    lines.append(
        f"[dim]@{entry.entry_type}[/dim]  [dim]key:[/dim] [{c['key']}]{entry.key}[/]"
    )
    lines.append("")

    # Keywords as badges
    if entry.keywords_list:
        kw_str = " ".join(
            f"[{c['tag_fg']} on {c['tag_bg']}] {k} [/]" for k in entry.keywords_list
        )
        lines.append(f"[bold]Keywords:[/bold]  {kw_str}")
    else:
        lines.append("[bold]Keywords:[/bold]  [dim](none)[/dim]")

    lines.append("")
    lines.append("─" * 50)
    lines.append("")

    # Key fields
    def field_line(label: str, value: str) -> str:
        if value:
            return f"[{c['required']}]{label:<12}[/] {value}"
        else:
            return f"[dim]{label:<12}[/dim] [dim](empty)[/dim]"

    standard_fields = [
        ("Author", "author"),
        ("Year", "year"),
        ("Journal", "journal"),
        ("DOI", "doi"),
        ("URL", "url"),
    ]

    for label, key in standard_fields:
        lines.append(field_line(label, entry.get_field(key)))

    # Raw extra fields
    if entry.raw_fields:
        lines.append("")
        lines.append("[dim]── Other fields ──[/dim]")
        for k, v in entry.raw_fields.items():
            if v:
                lines.append(f"  [dim]{k:<12}[/dim] {v[:80]}")

    # Abstract
    if entry.abstract:
        lines.append("")
        lines.append("[bold]Abstract:[/bold]")
        words = entry.abstract.split()
        current = ""
        for word in words:
            if len(current) + len(word) + 1 > 70:
                lines.append(f"  {current}")
                current = word
            else:
                current = f"{current} {word}".strip()
        if current:
            lines.append(f"  {current}")

    return "\n".join(lines)


def _render_raw(entry: BibEntry) -> Syntax:
    """Render entry as raw BibTeX with syntax highlighting."""
    return Syntax(entry_to_bibtex_str(entry), "bibtex", theme="monokai", word_wrap=True)


class EntryDetail(Widget):
    """Right pane: formatted entry detail view, togglable to raw BibTeX."""

    DEFAULT_CSS = """
    EntryDetail {
        height: 100%;
        overflow-y: scroll;
        padding: 1 2;
    }
    #detail-meta {
        height: auto;
        layout: horizontal;
        margin-bottom: 1;
    }
    #detail-read-state {
        width: auto;
        margin-right: 3;
    }
    #detail-rating {
        width: auto;
        margin-right: 3;
    }
    #detail-priority {
        width: auto;
        margin-right: 3;
    }
    #detail-file {
        width: auto;
    }
    #detail-url {
        width: auto;
        margin-left: 3;
    }
    #detail-content {
        height: auto;
        color: $text;
    }
    #detail-raw {
        display: none;
        height: 1fr;
    }
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self._entry: BibEntry | None = None
        self._raw_mode: bool = False
        self._pdf_base_dir: str = ""

    def on_mount(self) -> None:
        self.app.theme_changed_signal.subscribe(self, self._on_theme_changed)

    def _on_theme_changed(self, _theme) -> None:
        if self._entry is not None:
            self._refresh_content()

    def set_pdf_base_dir(self, base_dir: str) -> None:
        self._pdf_base_dir = base_dir

    def compose(self) -> ComposeResult:
        with Horizontal(id="detail-meta"):
            yield Label("", id="detail-read-state")
            yield Label("", id="detail-priority")
            yield Label("", id="detail-rating")
            yield Label("", id="detail-file")
            yield Label("", id="detail-url")
        yield Static("Select an entry to view details.", id="detail-content")
        yield TextArea("", id="detail-raw", read_only=True)

    def show_entry(self, entry: BibEntry | None) -> None:
        self._entry = entry
        self._refresh_content()

    @property
    def raw_mode(self) -> bool:
        return self._raw_mode

    def toggle_view(self) -> None:
        self._raw_mode = not self._raw_mode
        self._refresh_content()
        mode = "raw BibTeX" if self._raw_mode else "formatted"
        self.border_title = f"Entry Detail [{mode}]"

    def _file_icon(self, entry: BibEntry) -> str:
        if not entry.file:
            return " "
        path = parse_jabref_path(entry.file, self._pdf_base_dir)
        return "■" if os.path.exists(path) else "□"

    def _theme_colors(self) -> dict[str, str]:
        """Return Rich color strings derived from the current Textual theme.

        Only used for semantic highlights (title, key, field labels, tags).
        Plain body text uses CSS ``color: $text`` on the Static widget so that
        it automatically follows the theme without any Python involvement.
        """
        tv = self.app.theme_variables
        return {
            "title": tv.get("text-primary", "cyan"),
            "key": tv.get("text-accent", "yellow"),
            "required": tv.get("text-success", "green"),
            "optional": tv.get("text-accent", "blue"),
            "warning": tv.get("text-warning", "yellow"),
            "tag_fg": "white",
            "tag_bg": tv.get("primary", "dark_green"),
        }

    def _refresh_content(self) -> None:
        read_label = self.query_one("#detail-read-state", Label)
        priority_label = self.query_one("#detail-priority", Label)
        rating_label = self.query_one("#detail-rating", Label)
        file_label = self.query_one("#detail-file", Label)
        url_label = self.query_one("#detail-url", Label)
        content = self.query_one("#detail-content", Static)

        if self._entry is None:
            read_label.update("")
            priority_label.update("")
            rating_label.update("")
            file_label.update("")
            url_label.update("")
            content.update("Select an entry to view details.")
            self.query_one("#detail-raw", TextArea).display = False
            content.display = True
            return

        e = self._entry
        colors = self._theme_colors()

        state_label = e.read_state if e.read_state else "unset"
        read_label.update(f"[bold]Read:[/bold] {e.read_state_icon} {state_label}")

        if e.priority:
            priority_label.update(
                f"[bold]Priority:[/bold] {e.priority_icon} {e.priority_label}"
            )
        else:
            priority_label.update("[dim]Priority: —[/dim]")

        stars = e.rating_stars or "[dim]unrated[/dim]"
        rating_label.update(f"[bold]Rating:[/bold] [{colors['warning']}]{stars}[/]")

        icon = self._file_icon(e)
        if not e.file:
            file_label.update("[dim]PDF: —[/dim]")
        elif icon == "■":
            file_label.update("[bold]PDF:[/bold] ■")
        else:
            file_label.update("[bold]PDF:[/bold] [dim]□ not found[/dim]")

        if e.url:
            short = e.url if len(e.url) <= 40 else e.url[:37] + "…"
            url_label.update(f"[bold]🔗 URL:[/bold] {short}")
        else:
            url_label.update("[dim]🔗 URL: —[/dim]")

        raw = self.query_one("#detail-raw", TextArea)
        if self._raw_mode:
            content.display = False
            raw.display = True
            raw.load_text(entry_to_bibtex_str(e))
        else:
            raw.display = False
            content.display = True
            content.update(_render_entry(e, colors))
