"""Shell completion script generation.

This module generates shell completion scripts for Bash, Zsh, and Fish
that provide tab-completion for gaol commands and arguments.
"""

from __future__ import annotations

import os
from enum import Enum
from pathlib import Path


class Shell(str, Enum):
    """Supported shell types."""

    BASH = "bash"
    ZSH = "zsh"
    FISH = "fish"


class CompletionGenerator:
    """Generate shell completion scripts.

    Generates completion scripts that leverage Click's built-in completion
    support while adding dynamic completions for container names, profiles,
    and runtimes.

    Example:
        >>> gen = CompletionGenerator()
        >>> script = gen.generate(Shell.BASH)
        >>> print(script)  # Prints bash completion script
    """

    def __init__(self) -> None:
        """Initialize the completion generator."""
        self._app_name = "gaol"

    def generate(self, shell: Shell | str) -> str:
        """Generate completion script for the specified shell.

        Args:
            shell: Shell type (bash, zsh, or fish).

        Returns:
            Shell completion script as string.

        Raises:
            ValueError: If shell type is not supported.
        """
        if isinstance(shell, str):
            shell = Shell(shell.lower())

        if shell == Shell.BASH:
            return self._generate_bash()
        elif shell == Shell.ZSH:
            return self._generate_zsh()
        elif shell == Shell.FISH:
            return self._generate_fish()
        else:
            raise ValueError(f"Unsupported shell: {shell}")

    def get_install_path(self, shell: Shell | str) -> Path:
        """Get the standard install location for completions.

        Args:
            shell: Shell type.

        Returns:
            Path to the completion file location.
        """
        if isinstance(shell, str):
            shell = Shell(shell.lower())

        home = Path.home()

        if shell == Shell.BASH:
            # XDG compliant location
            xdg_data = os.environ.get("XDG_DATA_HOME", str(home / ".local/share"))
            return Path(xdg_data) / "bash-completion" / "completions" / self._app_name
        elif shell == Shell.ZSH:
            # Common zsh completion directory
            return home / ".zsh" / "completions" / f"_{self._app_name}"
        elif shell == Shell.FISH:
            # XDG compliant location for fish
            xdg_config = os.environ.get("XDG_CONFIG_HOME", str(home / ".config"))
            return Path(xdg_config) / "fish" / "completions" / f"{self._app_name}.fish"
        else:
            raise ValueError(f"Unsupported shell: {shell}")

    def install(self, shell: Shell | str) -> Path:
        """Install completion script to standard location.

        Args:
            shell: Shell type.

        Returns:
            Path where the completion was installed.
        """
        path = self.get_install_path(shell)
        script = self.generate(shell)

        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(script)

        return path

    def _generate_bash(self) -> str:
        """Generate Bash completion script."""
        return f'''# Bash completion for {self._app_name}
# Generated by gaol shell-integration

_{self._app_name}_completion() {{
    local IFS=$'\\n'
    local response

    response=$(env COMP_WORDS="${{COMP_WORDS[*]}}" COMP_CWORD=$COMP_CWORD _{self._app_name.upper()}_COMPLETE=bash_complete $1)

    for completion in $response; do
        IFS=',' read -r type value <<< "$completion"
        if [[ $type == 'dir' ]]; then
            COMPREPLY=()
            compopt -o dirnames
        elif [[ $type == 'file' ]]; then
            COMPREPLY=()
            compopt -o default
        elif [[ $type == 'plain' ]]; then
            COMPREPLY+=("$value")
        fi
    done

    return 0
}}

_{self._app_name}_completion_setup() {{
    complete -o nosort -F _{self._app_name}_completion {self._app_name}
}}

_{self._app_name}_completion_setup
'''

    def _generate_zsh(self) -> str:
        """Generate Zsh completion script."""
        return f'''#compdef {self._app_name}
# Zsh completion for {self._app_name}
# Generated by gaol shell-integration

_{self._app_name}_completion() {{
    local -a completions
    local -a completions_with_descriptions
    local -a response
    (( ! $+commands[{self._app_name}] )) && return 1

    response=("${{(@f)$(env COMP_WORDS="${{words[*]}}" COMP_CWORD=$((CURRENT-1)) _{self._app_name.upper()}_COMPLETE=zsh_complete {self._app_name})}}")

    for key descr in "${{(@kv)response}}"; do
        if [[ "$descr" == "_" ]]; then
            completions+=("$key")
        else
            completions_with_descriptions+=("$key":"$descr")
        fi
    done

    if [ -n "$completions_with_descriptions" ]; then
        _describe -V unsorted completions_with_descriptions -U
    fi

    if [ -n "$completions" ]; then
        compadd -U -V unsorted -a completions
    fi
}}

if [[ $zsh_eval_context[-1] == loadautofun ]]; then
    _{self._app_name}_completion "$@"
else
    compdef _{self._app_name}_completion {self._app_name}
fi
'''

    def _generate_fish(self) -> str:
        """Generate Fish completion script."""
        return f'''# Fish completion for {self._app_name}
# Generated by gaol shell-integration

function _{self._app_name}_completion
    set -l response (env _{self._app_name.upper()}_COMPLETE=fish_complete COMP_WORDS=(commandline -cp) COMP_CWORD=(commandline -t) {self._app_name})

    for completion in $response
        set -l metadata (string split "," -- $completion)

        if test $metadata[1] = "dir"
            __fish_complete_directories $metadata[2]
        else if test $metadata[1] = "file"
            __fish_complete_path $metadata[2]
        else if test $metadata[1] = "plain"
            echo $metadata[2]
        end
    end
end

complete -c {self._app_name} -f -a "(_{self._app_name}_completion)"
'''


def get_supported_shells() -> list[str]:
    """Get list of supported shell names.

    Returns:
        List of shell names.
    """
    return [s.value for s in Shell]
