"""Logging, color output, and display utilities."""

import os
import re
import sys
from datetime import datetime

from .config import CC_TAG, DEFAULT_TAG, STATE_ATTACHED, STATE_DETACHED, Color

# --- Public filtering helpers ---


def exclude_cc_sessions(sessions: list[dict]) -> list[dict]:
    """Filter out Claude Code sessions."""
    return [s for s in sessions if _parse_session_tag(s["name"]) != CC_TAG]


def only_cc_sessions(sessions: list[dict]) -> list[dict]:
    """Keep only Claude Code sessions."""
    return [s for s in sessions if _parse_session_tag(s["name"]) == CC_TAG]


def get_latest_from(sessions: list[dict]) -> dict | None:
    """Get the most recent session from a list, preferring detached."""
    if not sessions:
        return None
    sessions = sorted(sessions, key=lambda s: s["name"], reverse=True)
    detached = [s for s in sessions if s["state"] == STATE_DETACHED]
    return detached[0] if detached else sessions[0]


def _colors_enabled() -> bool:
    """Check if color output should be enabled."""
    if os.environ.get("NO_COLOR"):
        return False
    return hasattr(sys.stdout, "isatty") and sys.stdout.isatty()


def _c(color: str) -> str:
    """Return color code if colors enabled, empty string otherwise."""
    return color if _colors_enabled() else ""


def log_info(msg: str) -> None:
    print(f"{_c(Color.CYAN)}>{_c(Color.NC)} {msg}")


def log_success(msg: str) -> None:
    print(f"{_c(Color.GREEN)}>{_c(Color.NC)} {msg}")


def log_warn(msg: str) -> None:
    print(f"{_c(Color.YELLOW)}>{_c(Color.NC)} {msg}")


def log_error(msg: str) -> None:
    print(f"{_c(Color.RED)}>{_c(Color.NC)} {msg}")


def log_conda(msg: str) -> None:
    print(f"{_c(Color.MAGENTA)}>{_c(Color.NC)} {msg}")


def _format_age(timestamp_str: str | None) -> str:
    """Format a screen timestamp as a human-readable age (e.g. '2h ago')."""
    if not timestamp_str:
        return ""
    try:
        ts = datetime.strptime(timestamp_str, "%m/%d/%Y %I:%M:%S %p")
        delta = datetime.now() - ts
        secs = int(delta.total_seconds())
        if secs < 60:
            return f"{secs}s ago"
        elif secs < 3600:
            return f"{secs // 60}m ago"
        elif secs < 86400:
            return f"{secs // 3600}h ago"
        else:
            days = secs // 86400
            return f"{days}d ago"
    except ValueError:
        return ""


def _shorten_path(path: str | None) -> str:
    """Shorten a path for display, using ~ for home dir."""
    if not path:
        return ""
    home = os.path.expanduser("~")
    if path.startswith(home):
        return "~" + path[len(home) :]
    return path


def _parse_session_tag(name: str) -> str | None:
    """Extract the tag (e.g. 'cc', 'dev') from a smriti session name.

    Format: <host>-<dir>-<hash>-<tag>-<YYYYMMDD-HHMMSS>
    Returns None for legacy session names.
    """
    match = re.match(r".*-(\w+)-\d{8}-\d{6}$", name)
    if match:
        return match.group(1)
    return None


def _parse_timestamp(timestamp_str: str | None) -> datetime | None:
    """Parse a screen timestamp string into a datetime."""
    if not timestamp_str:
        return None
    try:
        return datetime.strptime(timestamp_str, "%m/%d/%Y %I:%M:%S %p")
    except ValueError:
        return None


def format_session_list(
    sessions: list[dict],
    label: str,
    current_dir_pattern: str | None = None,
) -> None:
    """Pretty-print a list of sessions.

    Sessions are sorted by recency (newest first). Current-dir sessions are
    highlighted and the most recent one is annotated as 'latest'.
    """
    if not sessions:
        log_warn(f"No sessions found ({label.lower()}).")
        return

    # Sort by screen timestamp (newest first)
    sessions = sorted(
        sessions,
        key=lambda s: _parse_timestamp(s.get("timestamp")) or datetime.min,
        reverse=True,
    )

    # Find the latest session matching current dir pattern
    latest_name = None
    if current_dir_pattern:
        matching = [s for s in sessions if s["name"].startswith(current_dir_pattern)]
        if matching:
            detached = [s for s in matching if s["state"] == STATE_DETACHED]
            latest_name = detached[0]["name"] if detached else matching[0]["name"]

    # Most recent overall (first after sorting)
    most_recent_name = sessions[0]["name"] if sessions else None

    print(f"\n{_c(Color.BOLD)}{label} ({len(sessions)}):{_c(Color.NC)}\n")

    for s in sessions:
        is_current_dir = current_dir_pattern and s["name"].startswith(current_dir_pattern)
        is_latest = s["name"] == latest_name
        is_most_recent = s["name"] == most_recent_name

        # State
        if s["state"] == STATE_ATTACHED:
            state_str = f"{_c(Color.GREEN)}attached{_c(Color.NC)}"
        else:
            state_str = f"{_c(Color.DIM)}detached{_c(Color.NC)}"

        # Name color
        if is_current_dir:
            name_str = f"{_c(Color.CYAN)}{_c(Color.BOLD)}{s['name']}{_c(Color.NC)}"
        elif is_most_recent and not latest_name:
            name_str = f"{_c(Color.BOLD)}{s['name']}{_c(Color.NC)}"
        else:
            name_str = f"{_c(Color.DIM)}{s['name']}{_c(Color.NC)}"

        # Info tags
        tags = []

        # Session tag (cc, dev, etc.) — skip "session" (default)
        session_tag = _parse_session_tag(s["name"])
        if session_tag and session_tag == CC_TAG:
            tags.append(f"{_c(Color.MAGENTA)}claude{_c(Color.NC)}")
        elif session_tag and session_tag != DEFAULT_TAG:
            tags.append(f"{_c(Color.CYAN)}{session_tag}{_c(Color.NC)}")

        if is_latest:
            tags.append(f"{_c(Color.YELLOW)}latest{_c(Color.NC)}")
        elif is_most_recent and not latest_name:
            tags.append(f"{_c(Color.YELLOW)}recent{_c(Color.NC)}")

        # Age
        age = _format_age(s.get("timestamp"))
        if age:
            tags.append(f"{_c(Color.DIM)}{age}{_c(Color.NC)}")

        # Directory
        cwd = _shorten_path(s.get("cwd"))
        if cwd:
            dir_str = f"  {_c(Color.BLUE)}{cwd}{_c(Color.NC)}"
        else:
            dir_str = ""

        tag_str = f"  ({', '.join(tags)})" if tags else ""
        bullet = f"{_c(Color.BLUE)}>{_c(Color.NC)}" if is_current_dir else " "

        print(f"  {bullet} {name_str}  {state_str}{dir_str}{tag_str}")

    print()


def pick_session(sessions: list[dict]) -> dict | None:
    """Interactive session picker. Returns selected session or None."""
    # Sort by timestamp (newest first)
    sessions = sorted(
        sessions,
        key=lambda s: _parse_timestamp(s.get("timestamp")) or datetime.min,
        reverse=True,
    )

    print(f"\n{_c(Color.BOLD)}Select a session:{_c(Color.NC)}\n")
    for i, s in enumerate(sessions, 1):
        session_tag = _parse_session_tag(s["name"])
        tag_parts = []
        if session_tag and session_tag == CC_TAG:
            tag_parts.append(f"{_c(Color.MAGENTA)}claude{_c(Color.NC)}")
        elif session_tag and session_tag != DEFAULT_TAG:
            tag_parts.append(f"{_c(Color.CYAN)}{session_tag}{_c(Color.NC)}")

        state = (
            f"{_c(Color.GREEN)}attached{_c(Color.NC)}"
            if s["state"] == STATE_ATTACHED
            else f"{_c(Color.DIM)}detached{_c(Color.NC)}"
        )
        age = _format_age(s.get("timestamp"))
        if age:
            tag_parts.append(f"{_c(Color.DIM)}{age}{_c(Color.NC)}")

        cwd = _shorten_path(s.get("cwd"))
        dir_str = f"  {_c(Color.BLUE)}{cwd}{_c(Color.NC)}" if cwd else ""
        tag_str = f"  ({', '.join(tag_parts)})" if tag_parts else ""

        print(f"  {_c(Color.BOLD)}{i}{_c(Color.NC)}) {s['name']}" f"  {state}{dir_str}{tag_str}")

    print()
    try:
        choice = input(f"{_c(Color.CYAN)}>{_c(Color.NC)} Enter number (or q to cancel): ")
        choice = choice.strip()
        if choice.lower() == "q" or not choice:
            return None
        idx = int(choice) - 1
        if 0 <= idx < len(sessions):
            return sessions[idx]
        log_error(f"Invalid selection: {choice}")
    except (ValueError, EOFError, KeyboardInterrupt):
        print()
    return None
