"""Shell integration helpers for cortex."""

from __future__ import annotations

import os
import subprocess
from pathlib import Path
from typing import Optional, Tuple


# Alias definitions for bash/zsh
BASH_ZSH_ALIASES = """
# Cortex Export Aliases
# Generated by cortex - for Warp AI and other terminal AI integrations

# Full context export (all components)
alias ctx='cortex export context -'

# Lightweight exports (exclude large components)
alias ctx-light='cortex export context - --exclude skills --exclude mcp_docs'
alias ctx-rules='cortex export context - --include rules --include core'
alias ctx-agents='cortex export context - --include agents --include mcp_docs'
alias ctx-modes='cortex export context - --include modes --include core --include rules'

# Core framework only (FLAGS, PRINCIPLES, RULES)
alias ctx-core='cortex export context - --include core'

# Helper to list what's available
alias ctx-list='cortex export list'

# Helper to copy context to clipboard for pasting
alias ctx-copy='cortex export context - 2>/dev/null | pbcopy && echo "✓ Context copied to clipboard"'

# Quick management commands
alias ctx-agent-list='cortex agent list'
alias ctx-mode-list='cortex mode list'
alias ctx-tui='cortex tui'
"""

# Function definitions for fish
FISH_FUNCTIONS = """
# Cortex Export Functions
# Generated by cortex - for Warp AI and other terminal AI integrations

# Full context export (all components)
function ctx
    cortex export context -
end

# Lightweight exports (exclude large components)
function ctx-light
    cortex export context - --exclude skills --exclude mcp_docs
end

function ctx-rules
    cortex export context - --include rules --include core
end

function ctx-agents
    cortex export context - --include agents --include mcp_docs
end

function ctx-modes
    cortex export context - --include modes --include core --include rules
end

# Core framework only (FLAGS, PRINCIPLES, RULES)
function ctx-core
    cortex export context - --include core
end

# Helper to list what's available
function ctx-list
    cortex export list
end

# Helper to copy context to clipboard for pasting
function ctx-copy
    cortex export context - 2>/dev/null | pbcopy; and echo "✓ Context copied to clipboard"
end

# Quick management commands
function ctx-agent-list
    cortex agent list
end

function ctx-mode-list
    cortex mode list
end

function ctx-tui
    cortex tui
end
"""

MARKER_START = "# >>> cortex aliases >>>"
MARKER_END = "# <<< cortex aliases <<<"


def detect_shell() -> Tuple[str, Path]:
    """Detect the current shell and its RC file.

    Returns:
        Tuple of (shell_name, rc_file_path)

    Raises:
        RuntimeError: If shell cannot be detected
    """
    # Try SHELL environment variable first
    shell_env = os.environ.get("SHELL", "")
    shell_name = Path(shell_env).name if shell_env else ""

    # Detect RC file based on shell
    home = Path.home()

    if "bash" in shell_name:
        # Try .bashrc first, then .bash_profile
        bashrc = home / ".bashrc"
        bash_profile = home / ".bash_profile"
        if bashrc.exists() or not bash_profile.exists():
            return "bash", bashrc
        else:
            return "bash", bash_profile
    elif "zsh" in shell_name:
        return "zsh", home / ".zshrc"
    elif "fish" in shell_name:
        return "fish", home / ".config" / "fish" / "config.fish"
    else:
        # Try to detect by checking which RC files exist
        if (home / ".zshrc").exists():
            return "zsh", home / ".zshrc"
        elif (home / ".bashrc").exists():
            return "bash", home / ".bashrc"
        elif (home / ".bash_profile").exists():
            return "bash", home / ".bash_profile"
        elif (home / ".config" / "fish" / "config.fish").exists():
            return "fish", home / ".config" / "fish" / "config.fish"
        else:
            raise RuntimeError(
                "Could not detect shell. Supported shells: bash, zsh, fish. "
                "Please specify shell explicitly with --shell option."
            )


def get_aliases_content(shell: str) -> str:
    """Get the aliases/functions content for a specific shell.

    Args:
        shell: Shell name (bash, zsh, or fish)

    Returns:
        Aliases content as string

    Raises:
        ValueError: If shell is not supported
    """
    shell = shell.lower()
    if shell in ("bash", "zsh"):
        return f"{MARKER_START}\n{BASH_ZSH_ALIASES}\n{MARKER_END}\n"
    elif shell == "fish":
        return f"{MARKER_START}\n{FISH_FUNCTIONS}\n{MARKER_END}\n"
    else:
        raise ValueError(f"Unsupported shell: {shell}")


def check_aliases_installed(rc_file: Path) -> bool:
    """Check if aliases are already installed in RC file.

    Args:
        rc_file: Path to RC file

    Returns:
        True if aliases are installed, False otherwise
    """
    if not rc_file.exists():
        return False

    try:
        content = rc_file.read_text()
        return MARKER_START in content
    except Exception:
        return False


def install_aliases(
    shell: Optional[str] = None,
    rc_file: Optional[Path] = None,
    force: bool = False,
    dry_run: bool = False,
) -> Tuple[int, str]:
    """Install cortex aliases into shell RC file.

    Args:
        shell: Shell name (bash, zsh, fish). Auto-detected if None.
        rc_file: Path to RC file. Auto-detected if None.
        force: Reinstall even if already installed
        dry_run: Show what would be done without making changes

    Returns:
        Tuple of (exit_code, message)
    """
    # Detect shell and RC file if not provided
    try:
        if shell is None or rc_file is None:
            detected_shell, detected_rc = detect_shell()
            shell = shell or detected_shell
            rc_file = rc_file or detected_rc
    except RuntimeError as e:
        return 1, str(e)

    # Validate shell
    if shell not in ("bash", "zsh", "fish"):
        return 1, f"Unsupported shell: {shell}. Supported: bash, zsh, fish"

    # Check if already installed
    already_installed = check_aliases_installed(rc_file)
    if already_installed and not force:
        return 1, (
            f"Aliases already installed in {rc_file}\n"
            f"Use --force to reinstall or --uninstall to remove"
        )

    # Get aliases content
    try:
        aliases_content = get_aliases_content(shell)
    except ValueError as e:
        return 1, str(e)

    # Dry run - just show what would be added
    if dry_run:
        message = [
            f"Would install aliases to: {rc_file}",
            f"Shell: {shell}",
            "",
            "Content to be added:",
            "─" * 60,
            aliases_content,
            "─" * 60,
            "",
            "Run without --dry-run to actually install.",
        ]
        return 0, "\n".join(message)

    # Create parent directories if needed
    rc_file.parent.mkdir(parents=True, exist_ok=True)

    # Read existing content
    existing_content = ""
    if rc_file.exists():
        try:
            existing_content = rc_file.read_text()
        except Exception as e:
            return 1, f"Failed to read {rc_file}: {e}"

    # Remove old installation if forcing reinstall
    if force and already_installed:
        # Remove content between markers
        lines = existing_content.split("\n")
        filtered_lines = []
        skip = False
        for line in lines:
            if MARKER_START in line:
                skip = True
            elif MARKER_END in line:
                skip = False
                continue
            elif not skip:
                filtered_lines.append(line)
        existing_content = "\n".join(filtered_lines).rstrip() + "\n"

    # Append aliases
    new_content = existing_content
    if not new_content.endswith("\n\n"):
        new_content = new_content.rstrip() + "\n\n"
    new_content += aliases_content

    # Write to file
    try:
        rc_file.write_text(new_content)
    except Exception as e:
        return 1, f"Failed to write to {rc_file}: {e}"

    message = [
        f"✓ Aliases installed to: {rc_file}",
        f"Shell: {shell}",
        "",
        "Reload your shell to use the new aliases:",
        f"  source {rc_file}",
        "",
        "Available aliases:",
        "  ctx           - Export full context",
        "  ctx-light     - Export lightweight context",
        "  ctx-rules     - Export rules only",
        "  ctx-agents    - Export agents only",
        "  ctx-modes     - Export modes only",
        "  ctx-core      - Export core framework only",
        "  ctx-list      - List available components",
        "  ctx-copy      - Copy context to clipboard",
        "  ctx-agent-list - List agents",
        "  ctx-mode-list - List modes",
        "  ctx-tui       - Launch TUI",
        "",
        "Perfect for Warp AI and other terminal AI tools!",
    ]

    return 0, "\n".join(message)


def uninstall_aliases(
    shell: Optional[str] = None, rc_file: Optional[Path] = None, dry_run: bool = False
) -> Tuple[int, str]:
    """Uninstall cortex aliases from shell RC file.

    Args:
        shell: Shell name (bash, zsh, fish). Auto-detected if None.
        rc_file: Path to RC file. Auto-detected if None.
        dry_run: Show what would be done without making changes

    Returns:
        Tuple of (exit_code, message)
    """
    # Detect shell and RC file if not provided
    try:
        if shell is None or rc_file is None:
            detected_shell, detected_rc = detect_shell()
            shell = shell or detected_shell
            rc_file = rc_file or detected_rc
    except RuntimeError as e:
        return 1, str(e)

    # Check if installed
    if not check_aliases_installed(rc_file):
        return 1, f"Aliases not found in {rc_file}"

    # Read existing content
    try:
        existing_content = rc_file.read_text()
    except Exception as e:
        return 1, f"Failed to read {rc_file}: {e}"

    # Remove content between markers
    lines = existing_content.split("\n")
    filtered_lines = []
    skip = False
    removed_lines = []

    for line in lines:
        if MARKER_START in line:
            skip = True
            removed_lines.append(line)
        elif MARKER_END in line:
            skip = False
            removed_lines.append(line)
            continue
        elif skip:
            removed_lines.append(line)
        else:
            filtered_lines.append(line)

    new_content = "\n".join(filtered_lines).rstrip() + "\n"

    # Dry run - show what would be removed
    if dry_run:
        message = [
            f"Would remove aliases from: {rc_file}",
            "",
            "Lines to be removed:",
            "─" * 60,
        ]
        message.extend(removed_lines)
        message.extend(
            [
                "─" * 60,
                "",
                "Run without --dry-run to actually uninstall.",
            ]
        )
        return 0, "\n".join(message)

    # Write updated content
    try:
        rc_file.write_text(new_content)
    except Exception as e:
        return 1, f"Failed to write to {rc_file}: {e}"

    message = [
        f"✓ Aliases removed from: {rc_file}",
        "",
        "Reload your shell:",
        f"  source {rc_file}",
    ]

    return 0, "\n".join(message)


def show_aliases() -> str:
    """Show all available aliases with their commands.

    Returns:
        Formatted string showing all aliases
    """
    return """
Cortex Export Aliases
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Context Export:
  ctx              Export full context (all components)
  ctx-light        Export lightweight context (excludes skills, mcp_docs)
  ctx-rules        Export rules only
  ctx-agents       Export agents only
  ctx-modes        Export modes only
  ctx-core         Export core framework (FLAGS, PRINCIPLES, RULES)

Utilities:
  ctx-list         List available components
  ctx-copy         Copy context to clipboard (macOS)

Management:
  ctx-agent-list   List available agents
  ctx-mode-list    List available modes
  ctx-tui          Launch terminal UI

Usage Examples:
  # Export full context for Warp AI
  ctx

  # Export lightweight context
  ctx-light

  # Copy context to clipboard
  ctx-copy

Installation:
  # Install aliases for your shell
  cortex install aliases

  # Show what would be installed (dry-run)
  cortex install aliases --dry-run

  # Uninstall aliases
  cortex install aliases --uninstall
"""
