"""
Startup display banner for Claude MPM.

Shows welcome message, version info, ASCII art, and what's new section.
"""

import os
import re
import shutil
import subprocess  # nosec B404 - required for git operations
from pathlib import Path
from typing import List

from claude_mpm.utils.git_analyzer import is_git_repository

# ANSI color codes
CYAN = "\033[36m"  # Cyan for header highlight (Claude Code style)
DIM = "\033[2m"  # Dim text for subtle launch message
RESET = "\033[0m"

# Banner dimension defaults (will be calculated based on terminal width)
MIN_WIDTH = 100  # Minimum banner width
MAX_WIDTH = 200  # Maximum banner width
DEFAULT_WIDTH = 160  # Default if terminal width cannot be determined


def _get_terminal_width() -> int:
    """
    Get terminal width with reasonable bounds.

    Returns:
        Terminal width (75% of actual) clamped between MIN_WIDTH and MAX_WIDTH
    """
    try:
        full_width = shutil.get_terminal_size().columns
        # Use 75% of terminal width for more compact display
        width = int(full_width * 0.75)
        # Apply reasonable bounds
        return max(MIN_WIDTH, min(width, MAX_WIDTH))
    except Exception:
        # 75% of 160 = 120
        return 120


def _get_username() -> str:
    """Get username from environment or default to 'User'."""
    return os.environ.get("USER") or os.environ.get("USERNAME") or "User"


def _get_recent_commits(max_commits: int = 3) -> List[str]:
    """
    Get recent git commits for display in startup banner.

    Args:
        max_commits: Maximum number of commits to retrieve (default: 3)

    Returns:
        List of formatted commit strings (hash • relative_time • message)
        Empty list if not a git repo or if any error occurs

    Format: "a3f5b7c • 2 hours ago • fix: resolve critical error"
    """
    try:
        # Check if we're in a git repository
        if not is_git_repository("."):
            return []

        # Run git log with custom format (safe - no user input)
        result = subprocess.run(  # nosec B603 B607
            ["git", "log", "--format=%h • %ar • %s", f"-{max_commits}"],
            capture_output=True,
            text=True,
            check=True,
            timeout=2,
        )

        if not result.stdout.strip():
            return []

        # Split into lines and return
        commits = [
            line.strip() for line in result.stdout.strip().split("\n") if line.strip()
        ]
        return commits[:max_commits]

    except Exception:
        # Fail silently - return empty list on any error
        # (not a git repo, git not installed, timeout, etc.)
        return []


def _strip_ansi_codes(text: str) -> str:
    """Remove ANSI color codes from text."""
    ansi_escape = re.compile(r"\x1b\[[0-9;]*m")
    return ansi_escape.sub("", text)


def _get_display_width(text: str) -> int:
    """
    Calculate display width accounting for emojis and wide characters.

    Args:
        text: Text to measure (without ANSI codes)

    Returns:
        Display width in terminal columns
    """
    width = 0
    for char in text:
        # Emoji and wide characters take 2 columns
        if ord(char) > 0x1F000:  # Emoji range
            width += 2
        else:
            width += 1
    return width


def _parse_changelog_highlights(max_items: int = 3, max_width: int = 130) -> List[str]:
    """
    Parse CHANGELOG.md to extract highlights from latest version.

    Args:
        max_items: Maximum number of highlights to return
        max_width: Maximum width for each highlight

    Returns:
        List of formatted bullet points for display.
    """
    changelog_path = Path(__file__).parent.parent.parent.parent / "CHANGELOG.md"

    if not changelog_path.exists():
        return ["No changelog available"]

    try:
        with open(changelog_path, encoding="utf-8") as f:
            lines = f.readlines()

        # Find latest version section (skip [Unreleased])
        in_version_section = False
        highlights = []

        for i, line in enumerate(lines):
            line = line.rstrip()

            # Skip unreleased section
            if line.startswith("## [Unreleased]"):
                continue

            # Found latest version
            if line.startswith("## [") and not in_version_section:
                in_version_section = True
                continue

            # Next version section means we're done
            if line.startswith("## [") and in_version_section:
                break

            # Extract any bullet points from any section in latest version
            if in_version_section:
                # Skip section headers
                if line.startswith("###"):
                    continue

                # Extract bullet points
                if line.startswith("-"):
                    # Get first line of multi-line items
                    item = line[2:].strip()  # Remove "- " prefix

                    # Clean up markdown formatting
                    item = item.replace("**", "")  # Remove bold markers

                    # Truncate if too long
                    if len(item) > max_width:
                        item = item[: max_width - 3] + "..."

                    highlights.append(item)

                    if len(highlights) >= max_items:
                        break

        if not highlights:
            highlights = ["See CHANGELOG.md for details"]

        return highlights[:max_items]

    except Exception:
        return ["See CHANGELOG.md for details"]


def _get_alien_art() -> List[str]:
    """Return multi-alien ASCII art with teal/cyan highlighting."""
    return [
        f"{CYAN}▐▛███▜▌ ▐▛███▜▌{RESET}",  # Two aliens - Width: 15 chars
        f"{CYAN}▝▜█████▛▘▝▜█████▛▘{RESET}",  # Two aliens base - Width: 18 chars
        f"{CYAN}▘▘ ▝▝    ▘▘ ▝▝{RESET}",  # Two aliens feet - Width: 14 chars
    ]


def _format_logging_status(logging_level: str) -> str:
    """Format logging status with helpful indicator."""
    if logging_level == "OFF":
        return "Logging: OFF (default)"
    if logging_level == "DEBUG":
        return f"Logging: {logging_level} (verbose)"
    return f"Logging: {logging_level}"


def _get_cwd_display(max_width: int = 40) -> str:
    """Get current working directory, truncated if needed."""
    cwd = str(Path.cwd())

    if len(cwd) <= max_width:
        return cwd

    # Truncate from the left with ellipsis
    return "..." + cwd[-(max_width - 3) :]


def _count_mpm_skills() -> int:
    """
    Count user-level MPM skills from ~/.claude/skills/.

    Returns:
        Number of skill directories with SKILL.md files
    """
    try:
        user_skills_dir = Path.home() / ".claude" / "skills"
        if not user_skills_dir.exists():
            return 0

        # Count directories with SKILL.md (skill directories)
        skill_count = 0
        for item in user_skills_dir.iterdir():
            if item.is_dir():
                skill_file = item / "SKILL.md"
                if skill_file.exists():
                    skill_count += 1
            # Also count standalone .md files (legacy format)
            elif item.is_file() and item.suffix == ".md" and item.name != "README.md":
                skill_count += 1

        return skill_count
    except Exception:
        # Silent failure - return 0 if any error
        return 0


def _count_deployed_agents() -> int:
    """
    Count deployed agents from .claude/agents/.

    Returns:
        Number of deployed agent files
    """
    try:
        deploy_target = Path.cwd() / ".claude" / "agents"
        if not deploy_target.exists():
            return 0

        # Count .md files, excluding README and other docs
        agent_files = [
            f
            for f in deploy_target.glob("*.md")
            if not f.name.startswith(("README", "INSTRUCTIONS", "."))
        ]
        return len(agent_files)
    except Exception:
        # Silent failure - return 0 if any error
        return 0


def _format_two_column_line(
    left: str, right: str, left_panel_width: int, right_panel_width: int
) -> str:
    """
    Format a two-column line with precise width control.

    Args:
        left: Left panel content (will be centered in left_panel_width)
        right: Right panel content (will be left-aligned in right_panel_width)
        left_panel_width: Width of left panel in characters
        right_panel_width: Width of right panel in characters

    Returns:
        Formatted line with exact character widths
    """
    # Strip ANSI codes for width calculation
    left_display = _strip_ansi_codes(left)
    right_display = _strip_ansi_codes(right)

    # Calculate actual display width
    left_width = _get_display_width(left_display)
    right_width = _get_display_width(right_display)

    # Calculate padding for left panel (centered)
    left_padding = (left_panel_width - left_width) // 2
    right_padding = left_panel_width - left_width - left_padding

    # Format left panel with centering
    left_formatted = " " * left_padding + left + " " * right_padding

    # Format right panel (left-aligned)
    # Right panel content should exactly fill right_panel_width
    right_formatted = right + " " * (right_panel_width - right_width)

    return f"│{left_formatted}│ {right_formatted}│"


def display_startup_banner(
    version: str,
    logging_level: str,
    applied_migrations: List[str] | None = None,
) -> None:
    """
    Display startup banner with welcome message and info.

    Banner dynamically adjusts to terminal width with cyan header highlight
    (Claude Code style).

    Args:
        version: Claude MPM version string
        logging_level: Current logging level (OFF/INFO/DEBUG)
        applied_migrations: List of migration descriptions applied this session.
            If None or empty, migration section is not shown.
    """
    # Note: Banner is shown BEFORE "Launching Claude..." progress bar (in cli/__init__.py)
    # This ensures users see welcome message before background services start
    print()  # Empty line before banner

    # Get terminal width and calculate panel sizes
    terminal_width = _get_terminal_width()
    left_panel_width = int(terminal_width * 0.25)  # ~25% for left panel
    # -4 accounts for: 2 borders (│) + 2 column separators (│ and space)
    right_panel_width = terminal_width - left_panel_width - 4

    username = _get_username()

    # Get recent git commits for "Recent activity" section
    recent_commits = _get_recent_commits(max_commits=3)

    # Build header line with cyan highlight (Claude Code style)
    header = f"─── Claude MPM v{version} "
    header_padding = "─" * (terminal_width - len(header) - 2)  # -2 for ╭╮
    top_line = f"{CYAN}╭{header}{header_padding}╮{RESET}"

    # Build content lines (plain text, no color)
    lines = []

    # Migration section (only if migrations were applied this session)
    if applied_migrations:
        migration_count = len(applied_migrations)
        migration_header = f"Migrations applied: {migration_count}"
        lines.append(
            _format_two_column_line(
                "", migration_header, left_panel_width, right_panel_width
            )
        )
        # Show each migration as a bullet point
        for migration_desc in applied_migrations:
            # Truncate if needed
            max_width = right_panel_width - 4  # Leave room for bullet
            if len(migration_desc) > max_width:
                migration_desc = migration_desc[: max_width - 3] + "..."
            lines.append(
                _format_two_column_line(
                    "", f"  - {migration_desc}", left_panel_width, right_panel_width
                )
            )
        # Add separator after migrations section
        separator = "-" * right_panel_width
        lines.append(
            _format_two_column_line("", separator, left_panel_width, right_panel_width)
        )

    # Line 1: Empty left | "Recent activity" right
    lines.append(
        _format_two_column_line(
            "", "Recent activity", left_panel_width, right_panel_width
        )
    )

    # Lines 2-4: Welcome message + commit activity (3 lines total)
    welcome_msg = f"Welcome back {username}!"

    # Truncate commits to fit right panel width (leave 2 chars margin)
    max_commit_width = right_panel_width - 2
    truncated_commits = []
    for commit in recent_commits:
        if len(commit) > max_commit_width:
            truncated_commits.append(commit[: max_commit_width - 3] + "...")
        else:
            truncated_commits.append(commit)

    # Line 2: Welcome message | First commit or "No recent activity"
    if truncated_commits:
        lines.append(
            _format_two_column_line(
                welcome_msg, truncated_commits[0], left_panel_width, right_panel_width
            )
        )
    else:
        lines.append(
            _format_two_column_line(
                welcome_msg, "No recent activity", left_panel_width, right_panel_width
            )
        )

    # Line 3: Empty left | Second commit or empty
    if len(truncated_commits) >= 2:
        lines.append(
            _format_two_column_line(
                "", truncated_commits[1], left_panel_width, right_panel_width
            )
        )
    else:
        lines.append(
            _format_two_column_line("", "", left_panel_width, right_panel_width)
        )

    # Line 4: Empty left | Third commit or empty
    if len(truncated_commits) >= 3:
        lines.append(
            _format_two_column_line(
                "", truncated_commits[2], left_panel_width, right_panel_width
            )
        )
    else:
        lines.append(
            _format_two_column_line("", "", left_panel_width, right_panel_width)
        )

    # Line 5: Empty left | separator right
    separator = "─" * right_panel_width
    lines.append(
        _format_two_column_line("", separator, left_panel_width, right_panel_width)
    )

    # Line 6: Alien art line 1 | "What's new"
    alien_art = _get_alien_art()
    lines.append(
        _format_two_column_line(
            alien_art[0], "What's new", left_panel_width, right_panel_width
        )
    )

    # Lines 7-8: More alien art | changelog highlights
    max_highlight_width = right_panel_width - 5  # Leave some margin
    highlights = _parse_changelog_highlights(max_items=3, max_width=max_highlight_width)

    if len(highlights) >= 1:
        lines.append(
            _format_two_column_line(
                alien_art[1], highlights[0], left_panel_width, right_panel_width
            )
        )
    else:
        lines.append(
            _format_two_column_line(
                alien_art[1], "", left_panel_width, right_panel_width
            )
        )

    if len(highlights) >= 2:
        lines.append(
            _format_two_column_line(
                alien_art[2], highlights[1], left_panel_width, right_panel_width
            )
        )
    else:
        lines.append(
            _format_two_column_line(
                alien_art[2], "", left_panel_width, right_panel_width
            )
        )

    # Line 9: Empty | third highlight or link
    if len(highlights) >= 3:
        lines.append(
            _format_two_column_line(
                "", highlights[2], left_panel_width, right_panel_width
            )
        )
    else:
        lines.append(
            _format_two_column_line(
                "", "/mpm-help for more", left_panel_width, right_panel_width
            )
        )

    # Line 10: Model info with counts | separator
    separator = "─" * right_panel_width
    agent_count = _count_deployed_agents()
    skill_count = _count_mpm_skills()

    # Format: "Sonnet 4.5 · 44 agents, 19 skills"
    if agent_count > 0 or skill_count > 0:
        counts_text = []
        if agent_count > 0:
            counts_text.append(f"{agent_count} agent{'s' if agent_count != 1 else ''}")
        if skill_count > 0:
            counts_text.append(f"{skill_count} skill{'s' if skill_count != 1 else ''}")
        model_info = f"Sonnet 4.5 · {', '.join(counts_text)}"
    else:
        model_info = "Sonnet 4.5 · Claude MPM"

    lines.append(
        _format_two_column_line(
            model_info, separator, left_panel_width, right_panel_width
        )
    )

    # Line 11: CWD | MPM Commands header
    cwd = _get_cwd_display(left_panel_width - 2)
    lines.append(
        _format_two_column_line(
            cwd, "MPM Commands", left_panel_width, right_panel_width
        )
    )

    # Line 12: Empty | /mpm command
    lines.append(
        _format_two_column_line(
            "", "  /mpm        - MPM overview", left_panel_width, right_panel_width
        )
    )

    # Line 13: Empty | /mpm-agents command
    lines.append(
        _format_two_column_line(
            "", "  /mpm-agents - Show agents", left_panel_width, right_panel_width
        )
    )

    # Line 14: Empty | /mpm-doctor command
    lines.append(
        _format_two_column_line(
            "", "  /mpm-doctor - Run diagnostics", left_panel_width, right_panel_width
        )
    )

    # Line 15: Empty | empty
    lines.append(_format_two_column_line("", "", left_panel_width, right_panel_width))

    # Line 16: Empty | autocomplete tip
    lines.append(
        _format_two_column_line(
            "", "Type / for autocomplete", left_panel_width, right_panel_width
        )
    )

    # Build bottom line (plain text, no color)
    bottom_line = f"╰{'─' * (terminal_width - 2)}╯"

    # Print banner (only header has cyan color)
    print(top_line)
    for line in lines:
        print(line)
    print(bottom_line)
    print()  # Empty line after banner


def should_show_banner(args) -> bool:
    """
    Determine if startup banner should be displayed.

    Skip banner for: --help, --version, info, doctor, config, configure, oauth commands
    """
    # Check for help/version flags
    if hasattr(args, "help") and args.help:
        return False
    if hasattr(args, "version") and args.version:
        return False

    # Check for commands that should skip banner
    # OAuth commands are lightweight utilities that should run immediately
    skip_commands = {"info", "doctor", "config", "configure", "oauth"}
    if hasattr(args, "command") and args.command in skip_commands:
        return False

    return True
