#!/usr/bin/env python3
"""
ARM GCC compiler implementation for embedded targets.
Used primarily for RP2040 and other ARM Cortex-M microcontrollers.
"""

from pathlib import Path
from typing import List, Optional
from .base import Compiler, CompileResult
from build_system.utils import run


class ARMGCCCompiler(Compiler):
    """ARM GCC compiler for embedded targets."""
    
    def __init__(self, executable: str = "arm-none-eabi-gcc", cpu: str = "cortex-m0plus"):
        """
        Initialize ARM GCC compiler.
        
        Args:
            executable: Compiler executable name
            cpu: Target CPU (e.g., "cortex-m0plus", "cortex-m4")
        """
        super().__init__("ARM GCC", executable)
        self.cpu = cpu
        self.thumb = True  # Use Thumb instruction set by default
    
    def compile(self,
                source: Path,
                output: Path,
                flags: Optional[List[str]] = None,
                defines: Optional[List[str]] = None,
                include_dirs: Optional[List[Path]] = None,
                dependency_file: Optional[Path] = None) -> CompileResult:
        """
        Compile a source file using ARM GCC.
        
        Args:
            source: Source file path
            output: Output object file path
            flags: Additional compiler flags
            defines: Preprocessor defines
            include_dirs: Additional include directories
            dependency_file: Path for dependency file (.d file)
        
        Returns:
            CompileResult with object file and dependency file paths
        
        Raises:
            subprocess.CalledProcessError: If compilation fails
        """
        # Ensure output directory exists
        output.parent.mkdir(parents=True, exist_ok=True)
        
        # Build command
        cmd = [self.executable]
        
        # Add CPU-specific flags
        cmd.append(f"-mcpu={self.cpu}")
        if self.thumb:
            cmd.append("-mthumb")
        
        # Add flags
        if flags:
            cmd.extend(flags)
        
        # Add compile-only flag
        cmd.append(self.get_compile_only_flag())
        
        # Add defines
        if defines:
            cmd.extend([self.get_define_flag(d) for d in defines])
        
        # Add include directories
        if include_dirs:
            cmd.extend([self.get_include_flag(d) for d in include_dirs])
        
        # Add dependency generation if requested
        dep_file = None
        if dependency_file:
            cmd.extend(["-MMD", "-MP"])
            dep_file = dependency_file
        
        # Add source file
        cmd.append(str(source))
        
        # Add output file
        cmd.extend(self.get_output_flag(output))
        
        # Run compilation
        run(cmd) # type: ignore
        
        return CompileResult(
            object_file=output,
            dependency_file=dep_file,
            success=True
        )
    
    def link(self,
             objects: List[Path],
             output: Path,
             flags: Optional[List[str]] = None,
             libraries: Optional[List[str]] = None,
             library_dirs: Optional[List[Path]] = None) -> bool:
        """
        Link object files into an executable using ARM GCC.
        
        Args:
            objects: List of object file paths
            output: Output executable path
            flags: Additional linker flags
            libraries: Libraries to link against
            library_dirs: Additional library search directories
        
        Returns:
            True if linking succeeded
        
        Raises:
            subprocess.CalledProcessError: If linking fails
        """
        # Ensure output directory exists
        output.parent.mkdir(parents=True, exist_ok=True)
        
        # Build command
        cmd = [self.executable]
        
        # Add CPU-specific flags
        cmd.append(f"-mcpu={self.cpu}")
        if self.thumb:
            cmd.append("-mthumb")
        
        # Add object files
        cmd.extend([str(obj) for obj in objects])
        
        # Add linker flags
        if flags:
            cmd.extend(flags)
        
        # Add library directories
        if library_dirs:
            cmd.extend([f"-L{lib_dir}" for lib_dir in library_dirs])
        
        # Add libraries
        if libraries:
            cmd.extend([f"-l{lib}" for lib in libraries])
        
        # Add output file
        cmd.extend(["-o", str(output)])
        
        # Run linker
        run(cmd) # type: ignore
        
        return True
    
    def get_object_extension(self) -> str:
        """Get object file extension for ARM GCC."""
        return ".o"
    
    def get_dependency_extension(self) -> str:
        """Get dependency file extension for ARM GCC."""
        return ".d"
    
    def supports_dependency_generation(self) -> bool:
        """ARM GCC supports automatic dependency generation."""
        return True
    
    def set_cpu(self, cpu: str) -> None:
        """
        Set the target CPU.
        
        Args:
            cpu: Target CPU name (e.g., "cortex-m0plus", "cortex-m4")
        """
        self.cpu = cpu
    
    def set_thumb(self, enabled: bool) -> None:
        """
        Enable or disable Thumb instruction set.
        
        Args:
            enabled: True to enable Thumb, False to disable
        """
        self.thumb = enabled


def check_arm_toolchain() -> bool:
    """
    Check if ARM toolchain is available.
    
    Returns:
        True if ARM toolchain is found, False otherwise
    """
    from build_system.utils import check_tool
    
    if check_tool("arm-none-eabi-gcc"):
        return True
    else:
        print(
            "ARM toolchain not found. Install arm-none-eabi-gcc:\n"
            "  Ubuntu/Debian: sudo apt install gcc-arm-none-eabi\n"
            "  macOS: brew install arm-none-eabi-gcc"
        )
