"""Shell completion scripts for brynq-runtime CLI."""

import os
from pathlib import Path


def detect_shell() -> str:
    """Detect the user's current shell from environment variables.

    Checks ``SHELL`` (Unix) and ``PSModulePath`` (PowerShell) to determine the
    active shell.

    Returns:
        One of ``'bash'``, ``'zsh'``, ``'powershell'``, or ``'unknown'``.
    """
    shell_env = os.environ.get("SHELL", "")
    if shell_env:
        name = os.path.basename(shell_env)
        if name == "bash":
            return "bash"
        if name == "zsh":
            return "zsh"

    if os.environ.get("PSModulePath"):
        return "powershell"

    return "unknown"


def generate_zsh_completion() -> str:
    """Return a zsh completion script for brynq-runtime.

    Uses ``_arguments`` syntax with descriptions for each subcommand and flag.
    The output can be written to a file in the user's fpath
    (e.g. ``~/.zsh/completions/_brynq-runtime``).

    Returns:
        A complete zsh completion script as a string.
    """
    return r'''#compdef brynq-runtime

_brynq-runtime() {
    local -a commands
    commands=(
        'start:Start the runtime server and open the app'
        'stop:Stop the runtime server'
        'status:Show runtime status'
        'models:List available models (local + cloud)'
        'login:OAuth login for a cloud provider'
        'chat:Interactive terminal chat'
        'chain:Run a multi-model chain'
        'batch:Process a batch file of prompts'
        'pipe:Headless pipe mode \- reads stdin, writes stdout'
        'watch:Watch a directory for new files and process them'
        'stats:Show learning subsystem usage statistics'
        'insights:Show AI workflow insights and patterns'
        'learn:Auto-detect preferences based on recent usage'
        'preferences:Manage Brynq learning preferences'
        'reset-learning:Clear all local learning data'
        'trends:Show 30-day trends'
        'costs:Show cost tracker report'
        'ab:Manage A/B tests'
        'network:Show network insights (requires telemetry opt-in)'
        'leaderboard:Show model leaderboard'
        'rate:Rate an agent'
        'reviews:Show reviews for an agent'
        'setup:Create a desktop shortcut for Brynq Chat'
        'monitor:Live htop-style process monitor'
        'dashboard:Open operator dashboard in browser'
        'tui:Rich terminal UI chat (requires textual)'
        'spawn:Spawn AI agents'
        'workflow:Manage DAG workflows'
    )

    _arguments -C \
        '(-h --help)'{-h,--help}'[Show help message]' \
        '(-V --version)'{-V,--version}'[Show version]' \
        '1:command:->command' \
        '*::arg:->args'

    case $state in
        command)
            _describe -t commands 'brynq-runtime command' commands
            ;;
        args)
            case $words[1] in
                start)
                    _arguments \
                        '--no-browser[Do not open the browser automatically]'
                    ;;
                login)
                    _arguments \
                        '1:provider:(claude gemini openai)'
                    ;;
                chat)
                    _arguments \
                        '(-m --model)'{-m,--model}'[Model to use (auto-detected if omitted)]:model' \
                        '--once[Non-interactive\: run one prompt and exit]' \
                        '(-v --verbose)'{-v,--verbose}'[Show strategy selection reasoning]' \
                        '--clipboard[Read prompt from clipboard when no prompt given]' \
                        '*:prompt'
                    ;;
                chain)
                    _arguments \
                        '1:prompt'
                    ;;
                batch)
                    _arguments \
                        '1:filepath:_files' \
                        '(-m --model)'{-m,--model}'[Model to use]:model' \
                        '(-s --strategy)'{-s,--strategy}'[Chain strategy]:strategy:(sequential fan-out debate refine single)' \
                        '(-o --output)'{-o,--output}'[Output file path for results]:output:_files' \
                        '(-f --format)'{-f,--format}'[Output format (default\: json)]:format:(json csv jsonl)'
                    ;;
                pipe)
                    _arguments \
                        '(-m --model)'{-m,--model}'[Force a specific model]:model' \
                        '(-s --strategy)'{-s,--strategy}'[Chain strategy]:strategy:(sequential fan-out debate refine single)' \
                        '--json[Output structured JSON]' \
                        '--format[Output format]:format:(text json csv tsv)' \
                        '--delimiter[Delimiter to split stdin into chunks]:delimiter' \
                        '--timeout[HTTP request timeout in seconds (default\: 120)]:timeout' \
                        '--batch-size[Number of lines to collect before sending (default\: 1)]:size'
                    ;;
                watch)
                    _arguments \
                        '1:directory:_directories' \
                        '--pattern[Glob pattern to match files]:pattern' \
                        '--chain[Chain template name to use]:chain' \
                        '--interval[Polling interval in seconds (default\: 5)]:interval'
                    ;;
                preferences)
                    _arguments \
                        '--set[Set a preference (key=value)]:preference'
                    ;;
                costs)
                    _arguments \
                        '--budget[Set a daily budget limit in USD]:budget'
                    ;;
                ab)
                    _arguments \
                        '--create[Create a test]:name' \
                        '--conclude[Conclude a test]:name' \
                        '--delete[Delete a test]:name'
                    ;;
                rate)
                    _arguments \
                        '1:agent_id' \
                        '--rating[Rating (1-5)]:rating:(1 2 3 4 5)' \
                        '--review[Optional review text]:review'
                    ;;
                reviews)
                    _arguments \
                        '1:agent_id'
                    ;;
                monitor)
                    _arguments \
                        '(-i --interval)'{-i,--interval}'[Refresh interval (default\: 2s)]:interval'
                    ;;
                dashboard)
                    _arguments \
                        '--port[Dashboard port (default\: 9999)]:port' \
                        '--no-browser[Do not open the browser]'
                    ;;
                spawn)
                    local -a spawn_commands
                    spawn_commands=(
                        'run:Spawn agents for a task'
                        'list:List running agents'
                        'kill:Kill an agent'
                    )
                    _arguments '1:spawn command:->spawn_cmd' '*::arg:->spawn_args'
                    case $state in
                        spawn_cmd)
                            _describe -t spawn_commands 'spawn command' spawn_commands
                            ;;
                        spawn_args)
                            case $words[1] in
                                run)
                                    _arguments \
                                        '(-t --task)'{-t,--task}'[Task description]:task' \
                                        '(-n --count)'{-n,--count}'[Number of agents]:count' \
                                        '--model[Model to use]:model' \
                                        '--backend[Backend (ollama/claude/gemini)]:backend:(ollama claude gemini)'
                                    ;;
                                kill)
                                    _arguments '1:agent name'
                                    ;;
                            esac
                            ;;
                    esac
                    ;;
                workflow)
                    local -a wf_commands
                    wf_commands=(
                        'create:Create workflow from JSON file'
                        'run:Start a workflow run'
                        'status:Show run status'
                        'list:List workflows'
                    )
                    _arguments '1:workflow command:->wf_cmd' '*::arg:->wf_args'
                    case $state in
                        wf_cmd)
                            _describe -t wf_commands 'workflow command' wf_commands
                            ;;
                        wf_args)
                            case $words[1] in
                                create)
                                    _arguments \
                                        '(-f --file)'{-f,--file}'[Path to workflow JSON]:file:_files'
                                    ;;
                                run)
                                    _arguments \
                                        '1:workflow id' \
                                        '(-i --input)'{-i,--input}'[Input prompt]:input'
                                    ;;
                                status)
                                    _arguments '1:run id'
                                    ;;
                            esac
                            ;;
                    esac
                    ;;
            esac
            ;;
    esac
}

_brynq-runtime "$@"
'''


def generate_powershell_completion() -> str:
    """Return a PowerShell completion script for brynq-runtime.

    Uses ``Register-ArgumentCompleter`` with a native script block that
    provides completions for all subcommands and their flags.  The output
    can be appended to the user's ``$PROFILE`` file.

    Returns:
        A complete PowerShell completion script as a string.
    """
    return r'''
$_brynqRuntimeCompleter = {
    param($wordToComplete, $commandAst, $cursorPosition)

    $commands = @{
        'start'        = 'Start the runtime server and open the app'
        'stop'         = 'Stop the runtime server'
        'status'       = 'Show runtime status'
        'models'       = 'List available models (local + cloud)'
        'login'        = 'OAuth login for a cloud provider'
        'chat'         = 'Interactive terminal chat'
        'chain'        = 'Run a multi-model chain'
        'batch'        = 'Process a batch file of prompts'
        'pipe'         = 'Headless pipe mode - reads stdin, writes stdout'
        'watch'        = 'Watch a directory for new files and process them'
        'stats'        = 'Show learning subsystem usage statistics'
        'insights'     = 'Show AI workflow insights and patterns'
        'learn'        = 'Auto-detect preferences based on recent usage'
        'preferences'  = 'Manage Brynq learning preferences'
        'reset-learning' = 'Clear all local learning data'
        'trends'       = 'Show 30-day trends'
        'costs'        = 'Show cost tracker report'
        'ab'           = 'Manage A/B tests'
        'network'      = 'Show network insights (requires telemetry opt-in)'
        'leaderboard'  = 'Show model leaderboard'
        'rate'         = 'Rate an agent'
        'reviews'      = 'Show reviews for an agent'
        'setup'        = 'Create a desktop shortcut for Brynq Chat'
        'monitor'      = 'Live htop-style process monitor'
        'dashboard'    = 'Open operator dashboard in browser'
        'tui'          = 'Rich terminal UI chat (requires textual)'
        'spawn'        = 'Spawn AI agents'
        'workflow'     = 'Manage DAG workflows'
    }

    $subcommandFlags = @{
        'start' = @(
            @{Name='--no-browser'; Tip='Do not open the browser automatically'}
        )
        'login' = @(
            @{Name='claude'; Tip='Anthropic Claude provider'}
            @{Name='gemini'; Tip='Google Gemini provider'}
            @{Name='openai'; Tip='OpenAI provider'}
        )
        'chat' = @(
            @{Name='-m'; Tip='Model to use (auto-detected if omitted)'}
            @{Name='--model'; Tip='Model to use (auto-detected if omitted)'}
            @{Name='--once'; Tip='Non-interactive: run one prompt and exit'}
            @{Name='-v'; Tip='Show strategy selection reasoning'}
            @{Name='--verbose'; Tip='Show strategy selection reasoning'}
            @{Name='--clipboard'; Tip='Read prompt from clipboard when no prompt given'}
        )
        'batch' = @(
            @{Name='-m'; Tip='Model to use'}
            @{Name='--model'; Tip='Model to use'}
            @{Name='-s'; Tip='Chain strategy'}
            @{Name='--strategy'; Tip='Chain strategy'}
            @{Name='-o'; Tip='Output file path for results'}
            @{Name='--output'; Tip='Output file path for results'}
            @{Name='-f'; Tip='Output format (default: json)'}
            @{Name='--format'; Tip='Output format (default: json)'}
        )
        'pipe' = @(
            @{Name='-m'; Tip='Force a specific model'}
            @{Name='--model'; Tip='Force a specific model'}
            @{Name='-s'; Tip='Chain strategy'}
            @{Name='--strategy'; Tip='Chain strategy'}
            @{Name='--json'; Tip='Output structured JSON'}
            @{Name='--format'; Tip='Output format'}
            @{Name='--delimiter'; Tip='Delimiter to split stdin into chunks'}
            @{Name='--timeout'; Tip='HTTP request timeout in seconds (default: 120)'}
            @{Name='--batch-size'; Tip='Number of lines to collect before sending (default: 1)'}
        )
        'watch' = @(
            @{Name='--pattern'; Tip='Glob pattern to match files'}
            @{Name='--chain'; Tip='Chain template name to use'}
            @{Name='--interval'; Tip='Polling interval in seconds (default: 5)'}
        )
        'preferences' = @(
            @{Name='--set'; Tip='Set a preference (key=value)'}
        )
        'costs' = @(
            @{Name='--budget'; Tip='Set a daily budget limit in USD'}
        )
        'ab' = @(
            @{Name='--create'; Tip='Create a test'}
            @{Name='--conclude'; Tip='Conclude a test'}
            @{Name='--delete'; Tip='Delete a test'}
        )
        'rate' = @(
            @{Name='--rating'; Tip='Rating (1-5)'}
            @{Name='--review'; Tip='Optional review text'}
        )
        'monitor' = @(
            @{Name='-i'; Tip='Refresh interval (default: 2s)'}
            @{Name='--interval'; Tip='Refresh interval (default: 2s)'}
        )
        'dashboard' = @(
            @{Name='--port'; Tip='Dashboard port (default: 9999)'}
            @{Name='--no-browser'; Tip='Do not open the browser'}
        )
        'spawn' = @(
            @{Name='run'; Tip='Spawn agents for a task'}
            @{Name='list'; Tip='List running agents'}
            @{Name='kill'; Tip='Kill an agent'}
        )
        'workflow' = @(
            @{Name='create'; Tip='Create workflow from JSON file'}
            @{Name='run'; Tip='Start a workflow run'}
            @{Name='status'; Tip='Show run status'}
            @{Name='list'; Tip='List workflows'}
        )
    }

    $spawnFlags = @{
        'run' = @(
            @{Name='-t'; Tip='Task description'}
            @{Name='--task'; Tip='Task description'}
            @{Name='-n'; Tip='Number of agents'}
            @{Name='--count'; Tip='Number of agents'}
            @{Name='--model'; Tip='Model to use'}
            @{Name='--backend'; Tip='Backend (ollama/claude/gemini)'}
        )
    }

    $workflowFlags = @{
        'create' = @(
            @{Name='-f'; Tip='Path to workflow JSON'}
            @{Name='--file'; Tip='Path to workflow JSON'}
        )
        'run' = @(
            @{Name='-i'; Tip='Input prompt'}
            @{Name='--input'; Tip='Input prompt'}
        )
    }

    $globalFlags = @(
        @{Name='-h'; Tip='Show help message'}
        @{Name='--help'; Tip='Show help message'}
        @{Name='-V'; Tip='Show version'}
        @{Name='--version'; Tip='Show version'}
    )

    $tokens = $commandAst.ToString().Split()
    $currentToken = $wordToComplete

    # Determine position context
    $subcommand = $null
    $nestedSub = $null
    for ($i = 1; $i -lt $tokens.Count; $i++) {
        $t = $tokens[$i]
        if ($null -eq $subcommand -and $commands.ContainsKey($t)) {
            $subcommand = $t
        } elseif ($subcommand -in @('spawn','workflow') -and $null -eq $nestedSub -and -not $t.StartsWith('-')) {
            $nestedSub = $t
        }
    }

    $results = @()

    if ($null -eq $subcommand) {
        # Complete top-level commands and global flags
        foreach ($key in $commands.Keys) {
            if ($key.StartsWith($currentToken)) {
                $results += [System.Management.Automation.CompletionResult]::new(
                    $key, $key, 'ParameterValue', $commands[$key])
            }
        }
        foreach ($flag in $globalFlags) {
            if ($flag.Name.StartsWith($currentToken)) {
                $results += [System.Management.Automation.CompletionResult]::new(
                    $flag.Name, $flag.Name, 'ParameterName', $flag.Tip)
            }
        }
    } elseif ($subcommand -in @('spawn','workflow') -and $null -ne $nestedSub) {
        # Nested subcommand flags (spawn run, workflow create, etc.)
        $flagMap = if ($subcommand -eq 'spawn') { $spawnFlags } else { $workflowFlags }
        if ($flagMap.ContainsKey($nestedSub)) {
            foreach ($flag in $flagMap[$nestedSub]) {
                if ($flag.Name.StartsWith($currentToken)) {
                    $results += [System.Management.Automation.CompletionResult]::new(
                        $flag.Name, $flag.Name, 'ParameterName', $flag.Tip)
                }
            }
        }
    } elseif ($subcommandFlags.ContainsKey($subcommand)) {
        # Subcommand-level completions
        foreach ($flag in $subcommandFlags[$subcommand]) {
            if ($flag.Name.StartsWith($currentToken)) {
                $type = if ($flag.Name.StartsWith('-')) { 'ParameterName' } else { 'ParameterValue' }
                $results += [System.Management.Automation.CompletionResult]::new(
                    $flag.Name, $flag.Name, $type, $flag.Tip)
            }
        }
    }

    return $results
}

Register-ArgumentCompleter -Native -CommandName brynq-runtime -ScriptBlock $_brynqRuntimeCompleter
'''


def generate_bash_completion() -> str:
    """Return a bash completion script for brynq-runtime.

    Returns:
        A complete bash completion script as a string.
    """
    return r'''
_brynq_runtime() {
    local cur prev commands
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    commands="start stop status models login chat chain batch pipe watch stats insights learn preferences reset-learning trends costs ab network leaderboard rate reviews setup monitor dashboard tui spawn workflow"

    if [ "$COMP_CWORD" -eq 1 ]; then
        COMPREPLY=( $(compgen -W "$commands -h --help -V --version" -- "$cur") )
        return 0
    fi

    case "${COMP_WORDS[1]}" in
        start)
            COMPREPLY=( $(compgen -W "--no-browser" -- "$cur") );;
        login)
            COMPREPLY=( $(compgen -W "claude gemini openai" -- "$cur") );;
        chat)
            COMPREPLY=( $(compgen -W "-m --model --once -v --verbose --clipboard" -- "$cur") );;
        batch)
            COMPREPLY=( $(compgen -W "-m --model -s --strategy -o --output -f --format" -- "$cur") );;
        pipe)
            COMPREPLY=( $(compgen -W "-m --model -s --strategy --json --format --delimiter --timeout --batch-size" -- "$cur") );;
        watch)
            COMPREPLY=( $(compgen -W "--pattern --chain --interval" -- "$cur") );;
        preferences)
            COMPREPLY=( $(compgen -W "--set" -- "$cur") );;
        costs)
            COMPREPLY=( $(compgen -W "--budget" -- "$cur") );;
        ab)
            COMPREPLY=( $(compgen -W "--create --conclude --delete" -- "$cur") );;
        rate)
            COMPREPLY=( $(compgen -W "--rating --review" -- "$cur") );;
        monitor)
            COMPREPLY=( $(compgen -W "-i --interval" -- "$cur") );;
        dashboard)
            COMPREPLY=( $(compgen -W "--port --no-browser" -- "$cur") );;
        spawn)
            COMPREPLY=( $(compgen -W "run list kill" -- "$cur") );;
        workflow)
            COMPREPLY=( $(compgen -W "create run status list" -- "$cur") );;
    esac
    return 0
}

complete -F _brynq_runtime brynq-runtime
'''


def install_completion(shell: str) -> None:
    """Append the completion script for *shell* to the user's shell config file.

    Supported shells: ``bash``, ``zsh``, ``powershell``.

    Args:
        shell: One of ``"bash"``, ``"zsh"``, or ``"powershell"``.

    Raises:
        ValueError: If *shell* is not one of the supported values.
    """
    shell = shell.lower()

    if shell == "bash":
        script = generate_bash_completion()
        target = Path.home() / ".bashrc"
    elif shell == "zsh":
        script = generate_zsh_completion()
        target = Path.home() / ".zshrc"
    elif shell == "powershell":
        script = generate_powershell_completion()
        profile = os.environ.get("PROFILE")
        if profile:
            target = Path(profile)
        else:
            # Default PowerShell profile location
            if os.name == "nt":
                docs = Path.home() / "Documents" / "WindowsPowerShell"
            else:
                docs = Path.home() / ".config" / "powershell"
            target = docs / "Microsoft.PowerShell_profile.ps1"
    else:
        raise ValueError(
            f"Unsupported shell: {shell!r}. "
            "Supported shells: bash, zsh, powershell"
        )

    target.parent.mkdir(parents=True, exist_ok=True)
    with open(target, "a", encoding="utf-8") as f:
        f.write("\n# brynq-runtime shell completion\n")
        f.write(script)
        f.write("\n")

    print(f"Completion installed to {target}")
