"""Profile screen: view/edit profile, stats, link accounts, send feedback."""

from textual import work
from textual.app import ComposeResult
from textual.binding import Binding
from textual.containers import Horizontal, Vertical
from rich.markup import escape
from textual.widgets import Button, Input, Select, Static

from skilark_cli.client import SkilarkClient
from skilark_cli.display import _progress_bar, _topic_bars

# Role display labels (matches onboarding.py ROLE_CHOICES)
_ROLE_LABELS = {
    "swe": "Software Engineer",
    "ai_ml": "ML / AI Engineer",
    "data_eng": "Data Engineer",
    "platform": "Platform / DevOps",
    "security": "Security Engineer",
    "product": "Product Manager",
    "research": "Research",
    "other": "Other",
}

_DIRECTION_LABELS = {
    "stay_sharp": "Stay sharp in my current role",
    "level_up": "Level up (promotion track)",
    "transition": "Transition to a new role",
}

_ROLE_OPTIONS = [(label, key) for key, label in _ROLE_LABELS.items()]
_DIRECTION_OPTIONS = [(label, key) for key, label in _DIRECTION_LABELS.items()]


class ProfilePane(Vertical, can_focus=True):
    """Profile view/edit, stats, link accounts, feedback.

    can_focus=True is needed so self.focus() works after closing edit/feedback,
    reclaiming focus for keybindings (e/l/f). SignalsPane doesn't need this
    because it delegates focus to its DataTable child.
    """

    BINDINGS = [
        Binding("e", "toggle_edit", "Edit", show=True),
        Binding("l", "link_account", "Link", show=True),
        Binding("f", "send_feedback", "Feedback", show=True),
    ]

    def __init__(self, client: SkilarkClient | None = None) -> None:
        super().__init__()
        self.client = client
        self._profile: dict = {}
        self._stats: dict = {}
        self._editing: bool = False

    def compose(self) -> ComposeResult:
        yield Static("", id="profile-error")
        yield Static("Loading profile...", id="profile-loading")
        with Vertical(id="profile-content"):
            # --- Profile info with inline edit ---
            with Vertical(id="profile-info"):
                yield Static("[bold]Your Profile[/bold]", id="profile-header")
                # Role
                with Horizontal(classes="profile-field"):
                    yield Static("[dim]Role[/dim]", classes="field-label")
                    yield Static("", id="profile-val-role", classes="field-value")
                    yield Select(
                        _ROLE_OPTIONS, id="profile-edit-role",
                        prompt="Select role", allow_blank=False,
                    )
                # Language
                with Horizontal(classes="profile-field"):
                    yield Static("[dim]Language[/dim]", classes="field-label")
                    yield Static("", id="profile-val-language", classes="field-value")
                    yield Input(
                        placeholder="e.g. Python, Go, Java",
                        id="profile-edit-language",
                    )
                # Direction
                with Horizontal(classes="profile-field"):
                    yield Static("[dim]Direction[/dim]", classes="field-label")
                    yield Static("", id="profile-val-direction", classes="field-value")
                    yield Select(
                        _DIRECTION_OPTIONS, id="profile-edit-direction",
                        prompt="Select direction", allow_blank=False,
                    )
                # Topics (read-only)
                with Horizontal(classes="profile-field"):
                    yield Static("[dim]Topics[/dim]", classes="field-label")
                    yield Static("", id="profile-val-topics", classes="field-value")
                # Edit actions
                yield Static(
                    "[dim]Save when done, Escape to cancel[/dim]",
                    id="profile-edit-hint",
                )
                yield Button("Save", id="profile-edit-save", variant="primary")

            yield Static("", id="profile-stats")
            yield Static("", id="profile-link-code")
            yield Input(placeholder="Type your feedback...", id="profile-feedback-input")
            yield Static("", id="profile-feedback-status")

    def on_mount(self) -> None:
        self.query_one("#profile-error").display = False
        self.query_one("#profile-link-code").display = False
        self.query_one("#profile-feedback-input").display = False
        self.query_one("#profile-feedback-status").display = False
        self.query_one("#profile-content").display = False
        self._hide_edit_widgets()
        self.focus()
        self._fetch_data()

    def _hide_edit_widgets(self) -> None:
        """Hide all edit-mode widgets."""
        self.query_one("#profile-edit-role").display = False
        self.query_one("#profile-edit-language").display = False
        self.query_one("#profile-edit-direction").display = False
        self.query_one("#profile-edit-hint").display = False
        self.query_one("#profile-edit-save").display = False

    def _show_edit_widgets(self) -> None:
        """Show all edit-mode widgets, hide display values.

        Topics field stays visible — it's read-only (derived from API).
        """
        self.query_one("#profile-val-role").display = False
        self.query_one("#profile-val-language").display = False
        self.query_one("#profile-val-direction").display = False
        self.query_one("#profile-edit-role").display = True
        self.query_one("#profile-edit-language").display = True
        self.query_one("#profile-edit-direction").display = True
        self.query_one("#profile-edit-hint").display = True
        self.query_one("#profile-edit-save").display = True

    def _show_display_widgets(self) -> None:
        """Show display values, hide edit widgets."""
        self.query_one("#profile-val-role").display = True
        self.query_one("#profile-val-language").display = True
        self.query_one("#profile-val-direction").display = True
        self._hide_edit_widgets()

    @work(thread=True, exit_on_error=False)
    def _fetch_data(self) -> None:
        if not self.client:
            self.app.call_from_thread(self._show_error, "No API client configured.")
            return
        try:
            profile = self.client.get_profile() or {}
            stats = self.client.get_stats()
            self.app.call_from_thread(self._populate, profile, stats)
        except Exception as exc:
            self.app.call_from_thread(self._show_error, str(exc))

    def _show_error(self, message: str) -> None:
        if not self.is_attached:
            return
        self.query_one("#profile-loading").display = False
        error = self.query_one("#profile-error", Static)
        error.update(f"Failed to load profile: {message}")
        error.display = True

    def _populate(self, profile: dict, stats: dict) -> None:
        if not self.is_attached:
            return
        self._profile = profile
        self._stats = stats
        self.query_one("#profile-loading").display = False
        self.query_one("#profile-error").display = False
        self.query_one("#profile-content").display = True
        self._render_info()
        self._render_stats()

    def _render_info(self) -> None:
        role = self._profile.get("current_role", "")
        language = self._profile.get("primary_language", "")
        direction = self._profile.get("career_direction", "")
        topics = self._profile.get("topics") or []

        role_label = _ROLE_LABELS.get(role, role)
        direction_label = _DIRECTION_LABELS.get(direction, direction)

        self.query_one("#profile-val-role", Static).update(escape(role_label))
        self.query_one("#profile-val-language", Static).update(escape(language))
        self.query_one("#profile-val-direction", Static).update(escape(direction_label))
        self.query_one("#profile-val-topics", Static).update(escape(", ".join(topics)))

    def _render_stats(self) -> None:
        streak = self._stats.get("streak", 0)
        total = self._stats.get("total_completed", 0)
        week_done = self._stats.get("week_completed", 0)
        week_goal = self._stats.get("week_goal", 10)
        topic_counts = self._stats.get("topic_counts") or {}

        week_bar = _progress_bar(week_done, week_goal, 10)

        lines = [
            f"[bold]Stats[/bold]  --  {streak} day streak",
            "",
            f"  [dim]This week[/dim]   {week_bar}  {week_done}/{week_goal}",
            f"  [dim]All time[/dim]    {total} challenges completed",
        ]

        topic_rows = _topic_bars(topic_counts)
        if topic_rows:
            lines.append("")
            max_label = max(len(t) for t, _, _ in topic_rows)
            for topic, bar, count in topic_rows:
                padding = " " * (max_label - len(topic))
                lines.append(f"  [dim]{escape(topic)}{padding}[/dim]  {bar}  {count:>3}")

        self.query_one("#profile-stats", Static).update("\n".join(lines))

    def action_toggle_edit(self) -> None:
        if self._editing:
            self._close_edit()
        else:
            role_select = self.query_one("#profile-edit-role", Select)
            current_role = self._profile.get("current_role", "")
            if current_role in _ROLE_LABELS:
                role_select.value = current_role
            else:
                role_select.value = Select.BLANK

            direction_select = self.query_one("#profile-edit-direction", Select)
            current_dir = self._profile.get("career_direction", "")
            if current_dir in _DIRECTION_LABELS:
                direction_select.value = current_dir
            else:
                direction_select.value = Select.BLANK

            self.query_one("#profile-edit-language", Input).value = (
                self._profile.get("primary_language", "")
            )

            self._show_edit_widgets()
            self._editing = True
            role_select.focus()

    def _close_edit(self) -> None:
        self._show_display_widgets()
        self._editing = False
        self.focus()

    def on_key(self, event) -> None:
        if event.key == "escape" and self._editing:
            self._close_edit()
            event.prevent_default()
            event.stop()
        elif event.key == "escape":
            feedback = self.query_one("#profile-feedback-input")
            if feedback.display:
                feedback.display = False
                self.focus()
                event.prevent_default()
                event.stop()

    def on_input_submitted(self, event: Input.Submitted) -> None:
        if event.input.id == "profile-feedback-input":
            self._submit_feedback()

    def on_button_pressed(self, event: Button.Pressed) -> None:
        if event.button.id == "profile-edit-save" and self._editing:
            self._save_profile()

    def _save_profile(self) -> None:
        role_val = self.query_one("#profile-edit-role", Select).value
        language = self.query_one("#profile-edit-language", Input).value.strip()
        dir_val = self.query_one("#profile-edit-direction", Select).value

        if role_val != Select.BLANK:
            self._profile["current_role"] = role_val
        if language:
            self._profile["primary_language"] = language
        if dir_val != Select.BLANK:
            self._profile["career_direction"] = dir_val

        self._close_edit()
        self._render_info()
        self._save_profile_api()

    @work(thread=True, exit_on_error=False)
    def _save_profile_api(self) -> None:
        if not self.client:
            return
        try:
            self.client.update_profile(
                current_role=self._profile.get("current_role"),
                primary_language=self._profile.get("primary_language"),
                career_direction=self._profile.get("career_direction"),
            )
        except Exception as exc:
            # Profile already updated locally; show dim warning
            self.app.call_from_thread(
                self._show_feedback_status, f"Profile saved locally (sync failed: {exc})"
            )

    def action_link_account(self) -> None:
        self._generate_link_code()

    @work(thread=True, exit_on_error=False)
    def _generate_link_code(self) -> None:
        if not self.client:
            return
        try:
            result = self.client.create_link_code()
            code = result.get("code", "")
            self.app.call_from_thread(self._show_link_code, code)
        except Exception as exc:
            self.app.call_from_thread(self._show_link_error, str(exc))

    def _show_link_code(self, code: str) -> None:
        if not self.is_attached:
            return
        display = self.query_one("#profile-link-code", Static)
        display.update(f"Link code: {code}\nSend this to your other Skilark channel. Expires in 10 min.")
        display.display = True
        self.focus()

    def _show_link_error(self, message: str) -> None:
        if not self.is_attached:
            return
        display = self.query_one("#profile-link-code", Static)
        display.update(f"Failed to generate link code: {message}")
        display.display = True
        self.focus()

    def action_send_feedback(self) -> None:
        feedback = self.query_one("#profile-feedback-input", Input)
        feedback.value = ""
        feedback.display = True
        feedback.focus()
        self.query_one("#profile-feedback-status").display = False

    def _submit_feedback(self) -> None:
        feedback_input = self.query_one("#profile-feedback-input", Input)
        message = feedback_input.value.strip()
        if not message:
            return
        feedback_input.display = False
        self.focus()
        self._send_feedback_api(message)

    @work(thread=True, exit_on_error=False)
    def _send_feedback_api(self, message: str) -> None:
        if not self.client:
            return
        try:
            self.client.send_feedback(message)
            self.app.call_from_thread(self._show_feedback_status, "Thanks for your feedback!")
        except Exception:
            self.app.call_from_thread(self._show_feedback_status, "Failed to send feedback. Try again later.")

    def _show_feedback_status(self, text: str) -> None:
        if not self.is_attached:
            return
        status = self.query_one("#profile-feedback-status", Static)
        status.update(text)
        status.display = True
