"""Cursor-style pill chat input bar for IuVe Avatar (0.2.1.x)."""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any, Callable

from .avatar_chat_input import input_viewport_height_px

AVATAR_CHAT_MODES = ("auto", "local", "cloud_assisted")
PRIMARY_BUTTON_SEND = "send"
PRIMARY_BUTTON_STOP = "stop"


def count_working_items(*, plan_running: bool, active_session_count: int) -> int:
    """Active plans/sessions shown in the working badge."""
    total = max(0, int(active_session_count))
    if plan_running:
        total += 1
    return total


def primary_button_mode(*, plan_running: bool) -> str:
    return PRIMARY_BUTTON_STOP if plan_running else PRIMARY_BUTTON_SEND


def resolve_tag_label(
    *,
    plan_running: bool,
    session_title: str,
    translate: Callable[[str], str],
) -> str | None:
    title = str(session_title or "").strip()
    if title:
        return title
    if plan_running:
        return translate("avatar.chat.tag.multitask")
    return None


def mode_label_key(mode: str) -> str:
    normalized = str(mode or "auto").strip().lower()
    if normalized not in AVATAR_CHAT_MODES:
        normalized = "auto"
    return f"avatar.chat.mode.{normalized}"


@dataclass
class AvatarChatInputBar:
    root: Any
    working_badge: Any
    pill: Any
    attach_btn: Any
    tag_chip: Any
    tag_label: Any
    tag_dismiss_btn: Any
    input_view: Any
    input_buffer: Any
    input_scroll: Any
    placeholder_label: Any
    mode_btn: Any
    mic_btn: Any
    send_btn: Any
    stop_btn: Any
    mode: str = "auto"
    tag_text: str | None = None


def build_avatar_chat_input_bar(
    gtk_module,
    *,
    translate: Callable[[str], str],
    on_send: Callable[[Any], None],
    on_stop: Callable[[Any], None],
    on_mic: Callable[[Any], None],
    on_attach: Callable[[Any], None],
    on_tag_dismiss: Callable[[Any], None],
    on_mode_changed: Callable[[str], None],
) -> AvatarChatInputBar:
    shell = gtk_module.Box(orientation=gtk_module.Orientation.VERTICAL, spacing=6)
    shell.add_css_class("avatar-chat-input-shell")
    shell.set_hexpand(True)
    shell.set_vexpand(False)

    working_badge = gtk_module.Label(label="")
    working_badge.set_xalign(0.0)
    working_badge.set_halign(gtk_module.Align.START)
    working_badge.add_css_class("avatar-chat-working-badge")
    working_badge.set_visible(False)
    shell.append(working_badge)

    pill = gtk_module.Box(orientation=gtk_module.Orientation.HORIZONTAL, spacing=8)
    pill.add_css_class("avatar-chat-pill")
    pill.set_hexpand(True)
    pill.set_vexpand(False)

    attach_btn = gtk_module.Button(label="+")
    attach_btn.add_css_class("avatar-chat-icon-btn")
    attach_btn.set_tooltip_text(translate("avatar.input.attach"))
    attach_btn.connect("clicked", on_attach)
    pill.append(attach_btn)

    tag_chip = gtk_module.Box(orientation=gtk_module.Orientation.HORIZONTAL, spacing=4)
    tag_chip.add_css_class("avatar-chat-tag-chip")
    tag_chip.set_valign(gtk_module.Align.CENTER)
    tag_chip.set_visible(False)
    tag_label = gtk_module.Label(label="")
    tag_label.add_css_class("avatar-chat-tag-label")
    tag_label.set_ellipsize(3)  # Pango.EllipsizeMode.END when available
    tag_chip.append(tag_label)
    tag_dismiss_btn = gtk_module.Button(label="×")
    tag_dismiss_btn.add_css_class("avatar-chat-tag-dismiss")
    tag_dismiss_btn.set_tooltip_text(translate("avatar.chat.tag.dismiss"))
    tag_dismiss_btn.connect("clicked", on_tag_dismiss)
    tag_chip.append(tag_dismiss_btn)
    pill.append(tag_chip)

    input_view = gtk_module.TextView()
    input_view.set_wrap_mode(gtk_module.WrapMode.WORD_CHAR)
    input_view.set_accepts_tab(False)
    input_view.add_css_class("chat-input")
    input_buffer = input_view.get_buffer()

    input_scroll = gtk_module.ScrolledWindow()
    input_scroll.set_policy(gtk_module.PolicyType.NEVER, gtk_module.PolicyType.AUTOMATIC)
    input_scroll.set_hexpand(True)
    input_scroll.set_vexpand(False)
    input_scroll.set_child(input_view)

    input_overlay = gtk_module.Overlay()
    input_overlay.set_hexpand(True)
    input_overlay.set_child(input_scroll)
    placeholder_label = gtk_module.Label(label=translate("avatar.input.placeholder"))
    placeholder_label.add_css_class("dim-label")
    placeholder_label.add_css_class("avatar-chat-placeholder")
    placeholder_label.set_halign(gtk_module.Align.START)
    placeholder_label.set_valign(gtk_module.Align.START)
    placeholder_label.set_margin_start(4)
    placeholder_label.set_margin_top(6)
    placeholder_label.set_wrap(True)
    placeholder_label.set_xalign(0.0)
    input_overlay.add_overlay(placeholder_label)
    pill.append(input_overlay)

    right_cluster = gtk_module.Box(orientation=gtk_module.Orientation.HORIZONTAL, spacing=6)
    right_cluster.set_valign(gtk_module.Align.END)

    mode_btn = gtk_module.MenuButton(label=translate(mode_label_key("auto")))
    mode_btn.add_css_class("avatar-chat-mode-btn")
    mode_btn.set_tooltip_text(translate("avatar.chat.mode.hint"))
    mode_popover = gtk_module.Popover()
    mode_popover.set_has_arrow(True)
    mode_box = gtk_module.Box(orientation=gtk_module.Orientation.VERTICAL, spacing=2)
    mode_box.set_margin_top(6)
    mode_box.set_margin_bottom(6)
    mode_box.set_margin_start(8)
    mode_box.set_margin_end(8)
    mode_buttons: dict[str, Any] = {}

    def _select_mode(mode_key: str, _btn=None) -> None:
        bar_mode = str(mode_key)
        mode_btn.set_label(translate(mode_label_key(bar_mode)))
        on_mode_changed(bar_mode)
        mode_popover.popdown()

    for mode_key in AVATAR_CHAT_MODES:
        mode_item = gtk_module.Button(label=translate(mode_label_key(mode_key)))
        mode_item.add_css_class("flat")
        mode_item.set_halign(gtk_module.Align.FILL)
        mode_item.connect("clicked", _select_mode, mode_key)
        mode_box.append(mode_item)
        mode_buttons[mode_key] = mode_item
    mode_popover.set_child(mode_box)
    mode_btn.set_popover(mode_popover)
    right_cluster.append(mode_btn)

    mic_btn = gtk_module.Button(label="🎤")
    mic_btn.add_css_class("avatar-chat-icon-btn")
    mic_btn.set_tooltip_text(translate("avatar.input.voice"))
    mic_btn.connect("clicked", on_mic)
    right_cluster.append(mic_btn)

    send_btn = gtk_module.Button(label="➤")
    send_btn.add_css_class("avatar-chat-send-btn")
    send_btn.add_css_class("suggested-action")
    send_btn.set_tooltip_text(translate("avatar.action.send"))
    send_btn.connect("clicked", on_send)

    stop_btn = gtk_module.Button(label="■")
    stop_btn.add_css_class("avatar-chat-stop-btn")
    stop_btn.set_tooltip_text(translate("avatar.action.stop"))
    stop_btn.connect("clicked", on_stop)
    stop_btn.set_visible(False)

    right_cluster.append(send_btn)
    right_cluster.append(stop_btn)
    pill.append(right_cluster)
    shell.append(pill)

    return AvatarChatInputBar(
        root=shell,
        working_badge=working_badge,
        pill=pill,
        attach_btn=attach_btn,
        tag_chip=tag_chip,
        tag_label=tag_label,
        tag_dismiss_btn=tag_dismiss_btn,
        input_view=input_view,
        input_buffer=input_buffer,
        input_scroll=input_scroll,
        placeholder_label=placeholder_label,
        mode_btn=mode_btn,
        mic_btn=mic_btn,
        send_btn=send_btn,
        stop_btn=stop_btn,
    )


def refresh_input_viewport(bar: AvatarChatInputBar, text: str) -> None:
    height = input_viewport_height_px(text)
    bar.input_scroll.set_size_request(-1, height)


def refresh_placeholder_visibility(bar: AvatarChatInputBar, *, has_text: bool) -> None:
    bar.placeholder_label.set_visible(not has_text)


def refresh_working_badge(
    bar: AvatarChatInputBar,
    *,
    plan_running: bool,
    active_session_count: int,
    translate: Callable[[str], str],
) -> None:
    count = count_working_items(
        plan_running=plan_running,
        active_session_count=active_session_count,
    )
    if count <= 0:
        bar.working_badge.set_visible(False)
        return
    bar.working_badge.set_label(translate("avatar.chat.working.badge").format(count=count))
    bar.working_badge.set_visible(True)


def refresh_primary_button(bar: AvatarChatInputBar, *, plan_running: bool) -> None:
    mode = primary_button_mode(plan_running=plan_running)
    bar.send_btn.set_visible(mode == PRIMARY_BUTTON_SEND)
    bar.stop_btn.set_visible(mode == PRIMARY_BUTTON_STOP)


def refresh_tag_chip(
    bar: AvatarChatInputBar,
    *,
    plan_running: bool,
    session_title: str,
    translate: Callable[[str], str],
) -> None:
    label = resolve_tag_label(
        plan_running=plan_running,
        session_title=session_title,
        translate=translate,
    )
    bar.tag_text = label
    if not label:
        bar.tag_chip.set_visible(False)
        return
    bar.tag_label.set_label(label)
    bar.tag_chip.set_visible(True)


def refresh_mode_button(bar: AvatarChatInputBar, *, mode: str, translate: Callable[[str], str]) -> None:
    bar.mode = str(mode or "auto")
    bar.mode_btn.set_label(translate(mode_label_key(bar.mode)))


def install_avatar_chat_file_drop(
    bar: AvatarChatInputBar,
    gtk_module,
    *,
    on_files_dropped: Callable[[list[str]], None],
) -> None:
    """Register GTK drag-and-drop target on the chat input pill (0.2.2.24)."""
    try:
        from gi.repository import Gdk, Gio
    except ImportError:
        return

    def _on_drop(_target, value, _x, _y) -> bool:
        paths: list[str] = []
        if value is None:
            return False
        if hasattr(value, "get_files"):
            for file_obj in value.get_files() or []:
                path = file_obj.get_path()
                if path:
                    paths.append(str(path))
        elif isinstance(value, (list, tuple)):
            for item in value:
                if isinstance(item, str):
                    paths.append(item)
        if not paths:
            return False
        on_files_dropped(paths)
        return True

    drop_target = gtk_module.DropTarget.new(Gdk.FileList, Gdk.DragAction.COPY)
    drop_target.connect("drop", _on_drop)
    bar.pill.add_controller(drop_target)

    input_drop = gtk_module.DropTarget.new(Gdk.FileList, Gdk.DragAction.COPY)
    input_drop.connect("drop", _on_drop)
    bar.input_view.add_controller(input_drop)
