from __future__ import annotations

from textual import on, work
from textual.app import ComposeResult
from textual.containers import Vertical, VerticalScroll
from textual.events import Key
from textual.screen import Screen
from textual.widgets import (
    Button,
    Input,
    Label,
    ListItem,
    ListView,
    Static,
    TabbedContent,
    TabPane,
    TextArea,
)

from termchat.themes import THEMES


# ── Status options ────────────────────────────────────────────────

STATUSES = [
    ("available", "[green]\u2022[/]  available", "you're online"),
    ("away", "[yellow]\u2022[/]  away", "you'll get notifications"),
    ("dnd", "[red]\u2022[/]  do not disturb", "notifications silenced"),
]


class ThemeItem(ListItem):
    def __init__(self, theme_name: str, is_dark: bool, primary: str, secondary: str, accent: str, error: str, bg: str) -> None:
        super().__init__()
        self.theme_name = theme_name
        self._is_dark = is_dark
        self._primary = primary
        self._secondary = secondary
        self._accent = accent
        self._error = error
        self._bg = bg

    def compose(self) -> ComposeResult:
        dots = (
            f"[{self._primary}]\u2588\u2588[/]"
            f"[{self._secondary}]\u2588\u2588[/]"
            f"[{self._accent}]\u2588\u2588[/]"
            f"[{self._error}]\u2588\u2588[/]"
            f"[{self._bg}]\u2588\u2588[/]"
        )
        tag = " [dim]light[/]" if not self._is_dark else ""
        yield Static(f"{self.theme_name}{tag}  {dots}", classes="theme-preview")


class StatusOption(ListItem):
    def __init__(self, key: str, label: str, desc: str) -> None:
        super().__init__()
        self.status_key = key
        self._label = label
        self._desc = desc

    def compose(self) -> ComposeResult:
        yield Static(f"{self._label}  [dim]{self._desc}[/]")


# ── Settings Screen ──────────────────────────────────────────────


class SettingsScreen(Screen[str | None]):

    BINDINGS = [
        ("escape", "go_back", "back"),
    ]

    def __init__(self, user: dict | None = None) -> None:
        super().__init__()
        self._user = user or {}
        self._original_theme: str | None = None
        self._profile_changed: bool = False

    def compose(self) -> ComposeResult:
        with Vertical(id="settings-screen"):
            yield Static(
                " [bold $primary]SETTINGS[/]  [dim]esc to close[/]",
                id="settings-header",
            )
            with TabbedContent(
                "Profile", "Account", "Appearance", "About",
                id="settings-tabs",
            ):
                with TabPane("Profile", id="tab-profile"):
                    yield Static("[dim]display name[/]", classes="settings-label")
                    yield Input(
                        value=self._user.get("display_name", ""),
                        placeholder="display name",
                        id="settings-display-name",
                    )
                    yield Static("[dim]pronouns[/]", classes="settings-label")
                    yield Input(
                        value=self._user.get("pronouns") or "",
                        placeholder="e.g. they/them",
                        id="settings-pronouns",
                    )
                    yield Static("[dim]bio[/]", classes="settings-label")
                    yield TextArea(
                        self._user.get("bio") or "",
                        id="settings-bio",
                    )
                    yield Label("", id="profile-save-status")
                    yield Button("save profile", id="save-profile-btn", variant="primary")

                with TabPane("Account", id="tab-account"):
                    yield Static("[bold]change password[/]", classes="settings-section-title")
                    yield Static("[dim]current password[/]", classes="settings-label")
                    yield Input(
                        placeholder="current password",
                        password=True,
                        id="settings-current-pw",
                    )
                    yield Static("[dim]new password[/]", classes="settings-label")
                    yield Input(
                        placeholder="new password (min 6 chars)",
                        password=True,
                        id="settings-new-pw",
                    )
                    yield Static("[dim]confirm new password[/]", classes="settings-label")
                    yield Input(
                        placeholder="confirm new password",
                        password=True,
                        id="settings-confirm-pw",
                    )
                    yield Label("", id="pw-error")
                    yield Button("change password", id="change-pw-btn", variant="primary")
                    yield Static("", classes="settings-spacer")
                    yield Button("logout", id="logout-btn", variant="error")

                with TabPane("Appearance", id="tab-appearance"):
                    yield Static("[bold]status[/]", classes="settings-section-title")
                    yield ListView(id="settings-status-list")
                    yield Static("", classes="settings-spacer")
                    yield Static("[bold]theme[/]", classes="settings-section-title")
                    yield Static("[dim]\u2191\u2193 preview  enter select[/]", classes="settings-hint")
                    yield ListView(id="settings-theme-list")

                with TabPane("About", id="tab-about"):
                    with VerticalScroll(id="about-scroll"):
                        yield Static(self._build_about_text(), id="about-text")

    async def on_mount(self) -> None:
        self._original_theme = self.app.theme

        # Populate status list
        status_list = self.query_one("#settings-status-list", ListView)
        for key, label, desc in STATUSES:
            await status_list.append(StatusOption(key, label, desc))

        # Populate theme list
        theme_list = self.query_one("#settings-theme-list", ListView)
        for t in THEMES:
            await theme_list.append(ThemeItem(
                t.name, t.dark, t.primary, t.secondary,
                t.accent, t.error, t.background,
            ))

    def _build_about_text(self) -> str:
        from termchat.config import API_URL, SERVER_URL
        username = self._user.get("username", "?")
        raw_created = self._user.get("created_at") or ""
        created = str(raw_created)[:10] if raw_created else "?"

        return (
            "[bold $primary]TERMCHAT[/] v1.5.0\n"
            f"terminal messaging for developers\n\n"
            f"[dim]server[/]   {SERVER_URL}\n"
            f"[dim]user[/]     @{username}\n"
            f"[dim]joined[/]   {created}\n\n"
            "[bold]commands[/]\n"
            "/code [lang] <code> \u2014 share code\n"
            "/file <path> \u2014 share a file\n"
            "/edit [text] \u2014 edit last message\n"
            "/delete \u2014 delete last message\n"
            "/status available|away|dnd\n"
            "/profile [@user] \u2014 view profile\n"
            "/search <text> \u2014 search messages\n"
            "/rename <name> \u2014 rename group\n"
            "/add @user \u2014 add to group\n"
            "/kick @user \u2014 remove from group\n"
            "/password \u2014 change password\n"
            "/clear \u2014 clear view\n"
            "/help \u2014 show help\n\n"
            "[bold]keybindings[/]\n"
            "enter \u2014 send\n"
            "shift+enter \u2014 newline\n"
            "pageup \u2014 load older messages\n"
            "ctrl+n \u2014 new chat\n"
            "ctrl+g \u2014 new group\n"
            "ctrl+f \u2014 search\n"
            "ctrl+d \u2014 delete/leave chat\n"
            "ctrl+o \u2014 settings\n"
            "ctrl+q \u2014 quit\n"
            "tab/shift+tab \u2014 cycle panels\n"
            "escape \u2014 focus sidebar / cancel"
        )

    def action_go_back(self) -> None:
        # Restore theme if it was only previewed
        if self._original_theme and self.app.theme != self._original_theme:
            # Check if theme was explicitly selected (saved to file)
            from termchat.config import CONFIG_DIR
            theme_file = CONFIG_DIR / "theme"
            if theme_file.exists():
                saved = theme_file.read_text().strip()
                if saved != self.app.theme:
                    self.app.theme = self._original_theme
            else:
                self.app.theme = self._original_theme
        if self._profile_changed:
            self.dismiss("profile_updated")
        else:
            self.dismiss(None)

    # ── Profile tab ────────────────────────────────────────────────

    @on(Button.Pressed, "#save-profile-btn")
    def on_save_profile(self) -> None:
        self._do_save_profile()

    @work(exclusive=True)
    async def _do_save_profile(self) -> None:
        display_name = self.query_one("#settings-display-name", Input).value.strip()
        pronouns = self.query_one("#settings-pronouns", Input).value.strip()
        bio = self.query_one("#settings-bio", TextArea).text.strip()
        status_label = self.query_one("#profile-save-status", Label)

        if not display_name:
            status_label.update("[red]display name required[/]")
            return

        try:
            api = self.app.api
            await api.update_profile(
                display_name=display_name,
                pronouns=pronouns,
                bio=bio,
            )
            status_label.update("[green]saved[/]")
            self._user["display_name"] = display_name
            self._user["pronouns"] = pronouns
            self._user["bio"] = bio
            self._profile_changed = True
        except Exception:
            status_label.update("[red]failed to save[/]")

    # ── Account tab ────────────────────────────────────────────────

    @on(Button.Pressed, "#change-pw-btn")
    def on_change_pw(self) -> None:
        self._do_change_pw()

    @work(exclusive=True)
    async def _do_change_pw(self) -> None:
        current = self.query_one("#settings-current-pw", Input).value
        new_pw = self.query_one("#settings-new-pw", Input).value
        confirm = self.query_one("#settings-confirm-pw", Input).value
        error_label = self.query_one("#pw-error", Label)

        if not current:
            error_label.update("[red]enter current password[/]")
            return
        if len(new_pw) < 6:
            error_label.update("[red]new password must be at least 6 characters[/]")
            return
        if new_pw != confirm:
            error_label.update("[red]passwords don't match[/]")
            return

        try:
            await self.app.api.change_password(current, new_pw)
            error_label.update("[green]password changed[/]")
            self.query_one("#settings-current-pw", Input).value = ""
            self.query_one("#settings-new-pw", Input).value = ""
            self.query_one("#settings-confirm-pw", Input).value = ""
        except Exception as exc:
            msg = str(exc)
            if "400" in msg:
                error_label.update("[red]current password is incorrect[/]")
            else:
                error_label.update("[red]failed to change password[/]")

    @on(Button.Pressed, "#logout-btn")
    def on_logout(self) -> None:
        self.dismiss("logout")

    # ── Appearance tab ─────────────────────────────────────────────

    @on(ListView.Selected, "#settings-status-list")
    def on_status_selected(self, event: ListView.Selected) -> None:
        item = event.item
        if isinstance(item, StatusOption):
            self._set_status(item.status_key)

    @work(exclusive=True)
    async def _set_status(self, status: str) -> None:
        try:
            await self.app.api.set_status(status)
            self.notify(f"status: {status}")
        except Exception:
            self.notify("failed", severity="error")

    @on(ListView.Highlighted, "#settings-theme-list")
    def on_theme_highlighted(self, event: ListView.Highlighted) -> None:
        item = event.item
        if isinstance(item, ThemeItem):
            self.app.theme = item.theme_name

    @on(ListView.Selected, "#settings-theme-list")
    def on_theme_selected(self, event: ListView.Selected) -> None:
        item = event.item
        if isinstance(item, ThemeItem):
            self.app.theme = item.theme_name
            from termchat.config import CONFIG_DIR
            theme_file = CONFIG_DIR / "theme"
            CONFIG_DIR.mkdir(parents=True, exist_ok=True)
            theme_file.write_text(item.theme_name)
            self._original_theme = item.theme_name
            self.notify(f"theme: {item.theme_name}")
