"""
Shell integration for turboalias
"""
import os
import re
import subprocess
from pathlib import Path
from typing import Dict, Optional

from .datastructures import SupportedShell


class ShellIntegration:
    """Handles shell detection and integration"""

    def __init__(self, config):
        self.config = config

    def detect_shells(self) -> Optional[SupportedShell]:
        """Detect the user's current default shell."""

        shell_path = os.environ.get("SHELL")

        if not shell_path:
            return None

        shell_name = Path(shell_path).name
        print(shell_name)
        if shell_name == "bash":
            return SupportedShell.BASH
        elif shell_name == "zsh":
            return SupportedShell.ZSH
        else:
            return None

    def get_shell_rc_file(self, shell) -> Path:
        """
        Get the most likely RC file path for bash or zsh,
        respecting environment variables and common OS conventions.

        Args:
            shell: The SupportedShell enum value or shell name (e.g., "bash", "zsh")

        Returns:
            A Path object to the shell's configuration file.

        Raises:
            ValueError: If the shell is not bash or zsh.
        """
        home = Path.home()

        # Handle SupportedShell enum
        if isinstance(shell, SupportedShell):
            shell_name = shell.value
        else:
            # Allow passing full paths like /bin/bash by getting the name
            shell_name = Path(shell).name

        if shell_name == "bash":
            # On macOS, interactive login shells often read .bash_profile.
            # We check if it exists first.
            bash_profile = home / ".bash_profile"
            if bash_profile.exists():
                return bash_profile

            # On most Linux distros and for non-login shells, .bashrc is used.
            return home / ".bashrc"

        elif shell_name == "zsh":
            # Zsh respects the $ZDOTDIR environment variable.
            # If it's set, the config file is $ZDOTDIR/.zshrc.
            if zdotdir := os.environ.get("ZDOTDIR"):
                return Path(zdotdir) / ".zshrc"

            # If $ZDOTDIR is not set, it defaults to home.
            return home / ".zshrc"

        else:
            raise ValueError(
                f"Unsupported shell: {shell_name}. Only 'bash' and 'zsh' are supported.")

    def is_turboalias_sourced(self, shell: str) -> bool:
        """Check if turboalias is already sourced in shell RC file"""
        rc_file = self.get_shell_rc_file(shell)

        if not rc_file.exists():
            return False

        with open(rc_file, 'r') as f:
            content = f.read()

        return str(self.config.shell_file) in content

    def add_source_line(self, shell: str) -> bool:
        """Add source line to shell RC file"""
        rc_file = self.get_shell_rc_file(shell)

        if self.is_turboalias_sourced(shell):
            return False

        # Add both the aliases source and a wrapper function for auto-reload
        source_lines = f'''
            # turboalias aliases
            [ -f "{self.config.shell_file}" ] && source "{self.config.shell_file}"

            # turboalias wrapper function for auto-reload
            turboalias() {{
                command turboalias "$@"
                local exit_code=$?
                # Reload aliases after add/remove/import/clear commands
                if [ $exit_code -eq 0 ] && [[ "$1" =~ ^(add|remove|import|clear|edit)$ ]]; then
                    source "{self.config.shell_file}" 2>/dev/null
                fi
                return $exit_code
            }}
            '''

        with open(rc_file, 'a') as f:
            f.write(source_lines)

        return True

    def generate_aliases_file(self):
        """Generate the aliases.sh file from config"""
        aliases = self.config.get_aliases()

        lines = [
            "#!/bin/bash",
            "# Generated by turboalias - DO NOT EDIT MANUALLY",
            "# Use 'turboalias' commands to manage aliases",
            ""
        ]

        # Group by category
        categorized = {}
        uncategorized = []

        for name, data in sorted(aliases.items()):
            category = data.get("category")
            if category:
                if category not in categorized:
                    categorized[category] = []
                categorized[category].append((name, data["command"]))
            else:
                uncategorized.append((name, data["command"]))

        # Write categorized aliases
        for category in sorted(categorized.keys()):
            lines.append(f"# {category}")
            for name, command in categorized[category]:
                lines.append(f'alias {name}="{self._escape_command(command)}"')
            lines.append("")

        # Write uncategorized aliases
        if uncategorized:
            if categorized:
                lines.append("# Other")
            for name, command in uncategorized:
                lines.append(f'alias {name}="{self._escape_command(command)}"')

        with open(self.config.shell_file, 'w') as f:
            f.write('\n'.join(lines))

    def _escape_command(self, command: str) -> str:
        """Escape command for shell alias"""
        # Escape double quotes and backslashes
        return command.replace('\\', '\\\\').replace('"', '\\"')

    def import_existing_aliases(self) -> Dict[str, str]:
        """Import aliases from current shell"""
        try:
            # Try to get aliases from current shell
            result = subprocess.run(
                ['bash', '-i', '-c', 'alias'],
                capture_output=True,
                text=True,
                timeout=5
            )

            aliases = {}
            # Parse alias output (format: alias name='command')
            pattern = re.compile(r"alias\s+([^=]+)='([^']*)'")

            for line in result.stdout.splitlines():
                match = pattern.match(line)
                if match:
                    name, command = match.groups()
                    # Skip turboalias-managed aliases
                    if not self.config.alias_exists(name):
                        aliases[name] = command

            return aliases
        except Exception as e:
            print(f"Warning: Could not import aliases: {e}")
            return {}

    def reload_shell_message(self) -> str:
        """Get message about reloading shell"""
        shell = self.detect_shells()
        if not shell:
            return ""

        commands = []

        rc_file = self.get_shell_rc_file(shell)
        commands.append(f"source {rc_file}")

        return f"Run: {' or '.join(commands)}"

    def auto_reload_aliases(self) -> bool:
        """Automatically reload aliases in the current shell process"""
        try:
            # Write a shell script that can be sourced by the parent shell
            reload_script = self.config.config_dir / ".reload_aliases.sh"
            
            with open(reload_script, 'w') as f:
                f.write(f'source "{self.config.shell_file}"\n')
            
            # Make it executable
            reload_script.chmod(0o755)
            
            # Print the source command that the user's shell can execute
            print(f"\n💡 To apply changes in this terminal, run:")
            print(f"   source {self.config.shell_file}")
            
            return True
        except Exception as e:
            print(f"Warning: Could not prepare auto-reload: {e}")
            return False
