from setuptools import setup, Extension, Command
import os
import sys
import subprocess
from configparser import ConfigParser
from setuptools.command.build_ext import build_ext as _build_ext

# Default values in case setup.cfg is not available
DEFAULT_INCLUDE_DIRS = ["/usr/include", "/usr/include/libindi", "/usr/local/include/libindi"]
DEFAULT_LIBRARIES = ["z", "cfitsio", "nova", "indiclient"]
DEFAULT_SWIG_OPTS = ["-v", "-Wall", "-c++", "-threads", "-I/usr/include", "-I/usr/include/libindi", "-I/usr/local/include/libindi"]

# Try to load build configurations from setup.cfg
try:
    config = ConfigParser()
    config.read("setup.cfg")
    
    if "build_ext" in config:
        include_dirs = config.get("build_ext", "include_dirs", fallback=":".join(DEFAULT_INCLUDE_DIRS)).split(":")
        libraries = config.get("build_ext", "libraries", fallback=" ".join(DEFAULT_LIBRARIES)).split()
        swig_opts_str = config.get("build_ext", "swig_opts", fallback=" ".join(DEFAULT_SWIG_OPTS))
        # Parse swig_opts, handling quotes properly
        swig_opts = []
        current_opt = ""
        in_quotes = False
        for char in swig_opts_str:
            if char == '"' or char == "'":
                in_quotes = not in_quotes
            elif char == ' ' and not in_quotes:
                if current_opt:
                    swig_opts.append(current_opt)
                    current_opt = ""
            else:
                current_opt += char
        if current_opt:
            swig_opts.append(current_opt)
    else:
        include_dirs = DEFAULT_INCLUDE_DIRS
        libraries = DEFAULT_LIBRARIES
        swig_opts = DEFAULT_SWIG_OPTS
except Exception as e:
    print(f"Warning: Error reading setup.cfg: {e}. Using default values.")
    include_dirs = DEFAULT_INCLUDE_DIRS
    libraries = DEFAULT_LIBRARIES
    swig_opts = DEFAULT_SWIG_OPTS

# Custom command to run SWIG
class SwigCommand(Command):
    description = "Run SWIG to generate Python bindings"
    user_options = []

    def initialize_options(self):
        pass

    def finalize_options(self):
        pass

    def run(self):
        # Find indiclientpython.i
        swig_file = "indiclientpython.i"
        search_paths = [".", "/pyindi-client"]
        
        swig_file_path = None
        for path in search_paths:
            full_path = os.path.join(path, swig_file)
            if os.path.exists(full_path):
                swig_file_path = full_path
                break
        
        if not swig_file_path:
            print(f"Error: {swig_file} not found in any of the search paths: {search_paths}")
            print(f"Current directory: {os.getcwd()}")
            print(f"Directory contents: {os.listdir('.')}")
            sys.exit(1)
            
        # Run SWIG command
        # Add -outdir PyIndi to place the generated Python module in the correct directory
        cmd = ["swig", "-python", "-c++", "-threads", "-outdir", "PyIndi"] + swig_opts + [swig_file_path]
        print(f"Running SWIG command: {' '.join(cmd)}")
        try:
            subprocess.check_call(cmd)
            print("SWIG command completed successfully")
            
            # Check if the wrapper file was generated
            wrapper_file = "indiclientpython_wrap.cxx" # Should still be generated in root
            python_module = "PyIndi/PyIndi.py" # Check in the output directory
            
            # Check for C++ wrapper
            if not os.path.exists(wrapper_file):
                print(f"Error: {wrapper_file} was not generated by SWIG")
                # Try to find it in other locations
                for path in [".", "/pyindi-client"]:
                    full_path = os.path.join(path, wrapper_file)
                    if os.path.exists(full_path):
                        print(f"Found {wrapper_file} at {full_path}")
                        # Copy it to the current directory
                        if path != ".":
                            import shutil
                            shutil.copy(full_path, wrapper_file)
                            print(f"Copied {full_path} to {wrapper_file}")
                        break
                else:
                    print(f"Could not find {wrapper_file} in any location")
                    sys.exit(1)
            
            # Check for Python module in the specified output directory
            if not os.path.exists(python_module):
                print(f"Error: {python_module} was not generated by SWIG in the PyIndi directory")
                # Optional: Add search logic here if needed, but primary check is the target dir
                sys.exit(1) # Exit if not found in the target dir

        except subprocess.CalledProcessError as e:
            print(f"Error running SWIG command: {e}")
            sys.exit(1)
        except FileNotFoundError:
            print("Error: SWIG not found. Please install SWIG.")
            sys.exit(1)

# Custom build_ext command that runs SWIG first
class BuildExt(_build_ext):
    def run(self):
        try:
            # Run SWIG first
            self.run_command('swig')
            # Then run the regular build_ext command
            _build_ext.run(self)
        except Exception as e:
            print(f"Error during build_ext: {e}")
            raise

# INDI Client Extension
ext_module = Extension(
    name="PyIndi._PyIndi",
    sources=["indiclientpython_wrap.cxx"],
    include_dirs=include_dirs,
    libraries=libraries,
    library_dirs=["/usr/lib", "/usr/lib64", "/lib", "/lib64"],
    extra_compile_args=["-fPIC"],
    extra_link_args=["-shared"],
)

setup(
    name="pyindi-client",
    version="2.1.7",  # Match version in pyproject.toml
    zip_safe=False,
    ext_modules=[ext_module],
    packages=["PyIndi"],
    package_data={
        "PyIndi": ["PyIndi.py"],
    },
    cmdclass={
        'swig': SwigCommand,
        'build_ext': BuildExt,
    },
)
