"""Core status widgets for the Kollabor CLI status area.

Provides the built-in widgets that display system information like
current directory, profile, model, status, stats, agent, and skills.
"""

import logging
from pathlib import Path
from typing import Any, Optional
from urllib.parse import urlparse

from core.ui.design_system import T, S

from .widget_registry import StatusWidgetRegistry, WidgetCategory, WidgetWidth

logger = logging.getLogger(__name__)


def _fg(text: str, color: tuple) -> str:
    """Apply foreground color to text."""
    r, g, b = color
    return f"\033[38;2;{r};{g};{b}m{text}\033[39m"


def _truncate(text: str, width: int, ellipsis: str = "...") -> str:
    """Truncate text to fit within width."""
    if len(text) <= width:
        return text
    if width <= len(ellipsis):
        return text[:width]
    return text[:width - len(ellipsis)] + ellipsis


class WidgetContext:
    """Context object passed to widget render functions.

    Provides access to services and configuration needed to render widgets.
    """

    def __init__(
        self,
        llm_service: Any = None,
        profile_manager: Any = None,
        agent_manager: Any = None,
        config: Any = None,
        tmux_plugin: Any = None,
        background_tasks_plugin: Any = None,
    ):
        self.llm_service = llm_service
        self.profile_manager = profile_manager
        self.agent_manager = agent_manager
        self.config = config
        self.tmux_plugin = tmux_plugin
        self.background_tasks_plugin = background_tasks_plugin


# =============================================================================
# CORE WIDGET RENDER FUNCTIONS
# =============================================================================

def render_cwd(width: int, ctx: Optional[WidgetContext]) -> str:
    """Render current working directory widget."""
    try:
        cwd = Path.cwd()
        home = Path.home()

        if cwd == home:
            display = "~"
        elif cwd.is_relative_to(home):
            rel_path = cwd.relative_to(home)
            parts = rel_path.parts
            if len(parts) > 2:
                display = f"~/{'/'.join(parts[-2:])}"
            else:
                display = f"~/{rel_path}"
        else:
            display = cwd.name or str(cwd)

        icon = _fg("cwd", T().ai_tag)
        text = _fg(_truncate(display, width - 5), T().text)
        return f"{icon} {text}"
    except Exception as e:
        logger.error(f"cwd widget error: {e}")
        return _fg("cwd ?", T().text_dim)


def render_profile(width: int, ctx: Optional[WidgetContext]) -> str:
    """Render active LLM profile widget."""
    try:
        name = "default"
        if ctx and ctx.profile_manager:
            profile = ctx.profile_manager.get_active_profile()
            if profile:
                name = profile.name

        icon = _fg("\u2318", T().secondary[0])  # Command symbol
        text = _fg(_truncate(name, width - 3), T().text)
        return f"{icon} {text}"
    except Exception as e:
        logger.error(f"profile widget error: {e}")
        return _fg("\u2318 ?", T().text_dim)


def render_model(width: int, ctx: Optional[WidgetContext]) -> str:
    """Render model name widget."""
    try:
        model = "unknown"
        if ctx and ctx.profile_manager:
            profile = ctx.profile_manager.get_active_profile()
            if profile:
                model = profile.get_model() or "unknown"

        text = _fg(_truncate(model, width), T().text)
        return text
    except Exception as e:
        logger.error(f"model widget error: {e}")
        return _fg("model?", T().text_dim)


def render_endpoint(width: int, ctx: Optional[WidgetContext]) -> str:
    """Render API endpoint widget."""
    try:
        endpoint = "local"
        if ctx and ctx.profile_manager:
            profile = ctx.profile_manager.get_active_profile()
            if profile:
                api_url = profile.get_endpoint() or ""
                if api_url:
                    try:
                        endpoint = urlparse(api_url).hostname or "local"
                    except Exception:
                        pass

        icon = _fg("@", T().text_dim)
        text = _fg(_truncate(endpoint, width - 2), T().text)
        return f"{icon} {text}"
    except Exception as e:
        logger.error(f"endpoint widget error: {e}")
        return _fg("@ ?", T().text_dim)


def render_status(width: int, ctx: Optional[WidgetContext]) -> str:
    """Render status indicator widget (Ready/Working)."""
    try:
        is_processing = False
        if ctx and ctx.llm_service:
            is_processing = ctx.llm_service.is_processing

        if is_processing:
            icon = _fg("*", T().warning[0])
            text = _fg("Working", T().warning[0])
        else:
            icon = _fg("*", T().ai_tag)
            text = _fg("Ready", T().ai_tag)

        result = f"{icon} {text}"
        return _truncate(result, width) if len("* Working") > width else result
    except Exception as e:
        logger.error(f"status widget error: {e}")
        return _fg("* ?", T().text_dim)


def render_stats(width: int, ctx: Optional[WidgetContext]) -> str:
    """Render message/token stats widget."""
    try:
        msgs = 0
        tokens = 0

        if ctx and ctx.llm_service and hasattr(ctx.llm_service, "session_stats"):
            stats = ctx.llm_service.session_stats
            msgs = stats.get("messages", 0)
            tokens = stats.get("input_tokens", 0) + stats.get("output_tokens", 0)

        # Format token count
        if tokens < 1000:
            token_display = f"{tokens}"
        elif tokens < 1000000:
            token_display = f"{tokens/1000:.1f}K"
        else:
            token_display = f"{tokens/1000000:.1f}M"

        text = _fg(f"{msgs} msg", T().text_dim) + _fg(" | ", T().text_dim) + _fg(f"{token_display} tok", T().text_dim)
        return text
    except Exception as e:
        logger.error(f"stats widget error: {e}")
        return _fg("0 msg | 0 tok", T().text_dim)


def render_agent(width: int, ctx: Optional[WidgetContext]) -> str:
    """Render active agent widget."""
    try:
        agent_name = None
        if ctx and ctx.agent_manager:
            agent = ctx.agent_manager.get_active_agent()
            if agent:
                agent_name = agent.name

        if not agent_name:
            return ""  # Return empty if no agent active

        icon = _fg("\u2301", T().thinking_tag)  # Electric arrow
        text = _fg(_truncate(agent_name, width - 3), T().text)
        return f"{icon} {text}"
    except Exception as e:
        logger.error(f"agent widget error: {e}")
        return _fg("\u2301 ?", T().text_dim)


def render_skills(width: int, ctx: Optional[WidgetContext]) -> str:
    """Render active skills widget."""
    try:
        # Hidden skills that shouldn't be shown
        hidden_skills = {"system_prompt"}

        active_skills = []
        total_skills = 0

        if ctx and ctx.agent_manager:
            agent = ctx.agent_manager.get_active_agent()
            if agent:
                all_skills = [s.name for s in agent.list_skills() if s.name not in hidden_skills]
                active_set = set(agent.active_skills) - hidden_skills
                active_skills = [s for s in all_skills if s in active_set]
                total_skills = len(all_skills)

        if not active_skills and total_skills == 0:
            return ""  # Return empty if no agent/skills

        # Build skills display
        if active_skills:
            # Show up to 2 active skills
            shown = active_skills[:2]
            skill_text = " ".join([_fg(s, T().text) for s in shown])
            remaining = total_skills - len(shown)
            if remaining > 0:
                skill_text += " " + _fg(f"+{remaining}", T().text_dim)
        else:
            skill_text = _fg("no-skill", T().text_dim)

        return skill_text
    except Exception as e:
        logger.error(f"skills widget error: {e}")
        return _fg("skills?", T().text_dim)


def render_tasks(width: int, ctx: Optional[WidgetContext]) -> str:
    """Render task info widget (pending tasks, current task)."""
    try:
        pending = 0
        current_task = None

        # Future: integrate with task manager
        # For now, return minimal info
        if pending == 0 and current_task is None:
            return _fg("\u2237 0 pending", T().text_dim)  # Four dots

        icon = _fg("\u2237", T().ai_tag)
        if current_task:
            text = _fg(_truncate(current_task, width - 3), T().text)
        else:
            text = _fg(f"{pending} pending", T().text)

        return f"{icon} {text}"
    except Exception as e:
        logger.error(f"tasks widget error: {e}")
        return _fg("\u2237 ?", T().text_dim)


def render_tmux(width: int, ctx: Optional[WidgetContext]) -> str:
    """Render tmux sessions count widget."""
    try:
        session_count = 0

        if ctx and ctx.tmux_plugin:
            sessions = getattr(ctx.tmux_plugin, "sessions", {})
            session_count = len(sessions)

        if session_count == 0:
            return _fg("0 tmux", T().text_dim)

        text = _fg(f"{session_count} tmux", T().text)
        return text
    except Exception as e:
        logger.error(f"tmux widget error: {e}")
        return _fg("? tmux", T().text_dim)


def render_bg_tasks(width: int, ctx: Optional[WidgetContext]) -> str:
    """Render background tasks count widget."""
    try:
        bg_count = 0

        if ctx and ctx.background_tasks_plugin:
            registry = getattr(ctx.background_tasks_plugin, "registry", None)
            if registry and hasattr(registry, "count_running"):
                bg_count = registry.count_running()

        if bg_count == 0:
            return _fg("0 bg", T().text_dim)

        text = _fg(f"{bg_count} bg", T().ai_tag)
        return text
    except Exception as e:
        logger.error(f"bg_tasks widget error: {e}")
        return _fg("? bg", T().text_dim)


def render_clock(width: int, ctx: Optional[WidgetContext]) -> str:
    """Render current time widget."""
    try:
        from datetime import datetime
        now = datetime.now()
        time_str = now.strftime("%H:%M:%S")
        return _fg(time_str, T().text_dim)
    except Exception as e:
        logger.error(f"clock widget error: {e}")
        return _fg("--:--:--", T().text_dim)


# =============================================================================
# REGISTRATION FUNCTION
# =============================================================================

def register_core_widgets(registry: StatusWidgetRegistry) -> None:
    """Register all core widgets with the registry.

    Args:
        registry: The StatusWidgetRegistry to register widgets with
    """
    logger.info("Registering core status widgets...")

    # Current Working Directory
    registry.register(
        id="cwd",
        name="Directory",
        description="Current working directory",
        render_fn=render_cwd,
        category=WidgetCategory.CORE,
        default_width="auto",
        min_width=8,
    )

    # LLM Profile
    registry.register(
        id="profile",
        name="Profile",
        description="Active LLM profile name",
        render_fn=render_profile,
        category=WidgetCategory.CORE,
        default_width="auto",
        min_width=6,
    )

    # Model Name
    registry.register(
        id="model",
        name="Model",
        description="Active model name",
        render_fn=render_model,
        category=WidgetCategory.CORE,
        default_width="auto",
        min_width=8,
    )

    # API Endpoint
    registry.register(
        id="endpoint",
        name="Endpoint",
        description="API endpoint hostname",
        render_fn=render_endpoint,
        category=WidgetCategory.CORE,
        default_width="auto",
        min_width=8,
    )

    # Status Indicator
    registry.register(
        id="status",
        name="Status",
        description="Ready/Working indicator",
        render_fn=render_status,
        category=WidgetCategory.CORE,
        default_width="auto",
        min_width=6,
    )

    # Message/Token Stats
    registry.register(
        id="stats",
        name="Stats",
        description="Message and token counts",
        render_fn=render_stats,
        category=WidgetCategory.CORE,
        default_width="auto",
        min_width=12,
    )

    # Active Agent
    registry.register(
        id="agent",
        name="Agent",
        description="Active agent name",
        render_fn=render_agent,
        category=WidgetCategory.CORE,
        default_width="auto",
        min_width=8,
    )

    # Active Skills
    registry.register(
        id="skills",
        name="Skills",
        description="Active skills list",
        render_fn=render_skills,
        category=WidgetCategory.CORE,
        default_width="auto",
        min_width=10,
    )

    # Tasks
    registry.register(
        id="tasks",
        name="Tasks",
        description="Pending/current task info",
        render_fn=render_tasks,
        category=WidgetCategory.CORE,
        default_width="auto",
        min_width=10,
    )

    # Tmux Sessions
    registry.register(
        id="tmux",
        name="Tmux",
        description="Active tmux session count",
        render_fn=render_tmux,
        category=WidgetCategory.CORE,
        default_width="auto",
        min_width=6,
    )

    # Background Tasks
    registry.register(
        id="bg-tasks",
        name="Background",
        description="Running background task count",
        render_fn=render_bg_tasks,
        category=WidgetCategory.CORE,
        default_width="auto",
        min_width=5,
    )

    # Clock
    registry.register(
        id="clock",
        name="Clock",
        description="Current time",
        render_fn=render_clock,
        category=WidgetCategory.CORE,
        default_width="8ch",
        min_width=8,
    )

    logger.info(f"Registered {len(registry.get_core_widgets())} core widgets")
