"""Bash shell completion generator."""

from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from ..models import CommandCompletion

__all__ = ["generate_bash"]


def _build_subcommand_case(cmd_name: str, cmd: CommandCompletion) -> str:
    """Build bash case statement for a command with subcommands."""
    subcmd_list = " ".join(sorted(cmd.subcommands.keys()))
    # Position 1 is subcommand selection
    subcmd_cases: list[str] = [f'                1) COMPREPLY=($(compgen -W "{subcmd_list}" -- "$cur"));;']

    # Build per-subcommand argument completions at position 2+
    for subcmd_name, subcmd in sorted(cmd.subcommands.items()):
        for arg in subcmd.args:
            if arg.completion_type in ("choices", "dynamic", "literal"):
                values_str = " ".join(arg.values)
                # Subcommand args start at position 2 (pos 1 is the subcommand itself)
                subcmd_cases.append(
                    f'                *) [[ "${{COMP_WORDS[2]}}" == "{subcmd_name}" ]] && '
                    f"[[ $pos -eq {arg.position + 1} ]] && "
                    f'COMPREPLY=($(compgen -W "{values_str}" -- "$cur"));;'
                )

    pos_block = "\n".join(subcmd_cases)
    return f"""            {cmd_name})
                case $pos in
{pos_block}
                esac
                ;;"""


def _build_help_case(cmd: CommandCompletion, all_commands: str) -> str:
    """Build bash case for help command with hierarchical completion.

    Position 1: complete with all commands
    Position 2+: complete subcommands based on the command at position 1
    """
    # Build case statements for commands that have subcommands
    subcmd_cases: list[str] = []
    for parent_name, parent_cmd in sorted(cmd.subcommands.items()):
        if parent_cmd.args:
            subcmds_str = " ".join(parent_cmd.args[0].values)
            subcmd_cases.append(f'                    {parent_name}) COMPREPLY=($(compgen -W "{subcmds_str}" -- "$cur"));;')

    subcmd_block = "\n".join(subcmd_cases) if subcmd_cases else "                    *) ;;"

    return f"""            help)
                if [[ $pos -eq 1 ]]; then
                    # Position 1: complete with all commands
                    COMPREPLY=($(compgen -W "{all_commands}" -- "$cur"))
                else
                    # Position 2+: complete subcommands based on COMP_WORDS[2]
                    case "${{COMP_WORDS[2]}}" in
{subcmd_block}
                    esac
                fi
                ;;"""


def _build_args_case(cmd_name: str, cmd: CommandCompletion) -> str | None:
    """Build bash case statement for a command with positional args."""
    pos_cases: list[str] = []
    for arg in cmd.args:
        if arg.completion_type in ("choices", "dynamic", "literal"):
            values_str = " ".join(arg.values)
            pos_cases.append(f'                {arg.position}) COMPREPLY=($(compgen -W "{values_str}" -- "$cur"));;')
        elif arg.completion_type == "file":
            pos_cases.append(f'                {arg.position}) COMPREPLY=($(compgen -f -- "$cur"));;')
        # hint and none types: no completion

    if not pos_cases:
        return None

    pos_block = "\n".join(pos_cases)
    return f"""            {cmd_name})
                case $pos in
{pos_block}
                esac
                ;;"""


def generate_bash(commands: dict[str, CommandCompletion]) -> str:
    """Generate bash completion script content.

    Args:
        commands: Dict mapping command name -> CommandCompletion

    Returns:
        The bash completion script content
    """
    cmd_list = " ".join(sorted(commands.keys()))

    # Build case statements for each command
    case_statements: list[str] = []
    for cmd_name, cmd in sorted(commands.items()):
        if cmd_name == "help":
            case_statements.append(_build_help_case(cmd, cmd_list))
        elif cmd.subcommands:
            case_statements.append(_build_subcommand_case(cmd_name, cmd))
        elif cmd.args:
            case_stmt = _build_args_case(cmd_name, cmd)
            if case_stmt:
                case_statements.append(case_stmt)

    case_block = "\n".join(case_statements) if case_statements else "            *) ;;"

    return f"""# Bash completion for pypr
# Generated by: pypr compgen bash

_pypr() {{
    local cur="${{COMP_WORDS[COMP_CWORD]}}"
    local cmd="${{COMP_WORDS[1]}}"
    local pos=$((COMP_CWORD - 1))

    if [[ $COMP_CWORD -eq 1 ]]; then
        COMPREPLY=($(compgen -W "{cmd_list}" -- "$cur"))
        return
    fi

    case "$cmd" in
{case_block}
    esac
}}

complete -F _pypr pypr
"""
