#!/usr/bin/env python3

from pybind11.setup_helpers import Pybind11Extension, build_ext
from setuptools import setup, find_packages
import pybind11
import sys
import platform
import os
from pathlib import Path

# Platform-specific compiler flags
extra_compile_args = []
extra_link_args = []

if sys.platform == "darwin":  # macOS
    extra_compile_args = [
        "-stdlib=libc++",
        "-mmacosx-version-min=10.14",
        "-fvisibility=hidden",
    ]
    extra_link_args = ["-stdlib=libc++", "-mmacosx-version-min=10.14"]
elif sys.platform.startswith("linux"):
    extra_compile_args = [
        "-fvisibility=hidden",
        "-fopenmp",
    ]
    extra_link_args = ["-fopenmp"]
elif sys.platform == "win32":
    extra_compile_args = ["/openmp"]
    extra_link_args = []

# Find Eigen headers
def find_eigen():
    """Find Eigen include directory."""
    import subprocess
    
    # Possible locations to check
    possible_paths = [
        Path("eigen-3.4.0"),  # Bundled with package
        Path("eigen"),        # Alternative bundled location
        Path("/usr/include/eigen3"),
        Path("/usr/local/include/eigen3"),
        Path("/opt/homebrew/include/eigen3"),
        Path("../eigen-3.4.0"),
        Path("../eigen"),
    ]
    
    # Check environment variable
    if "EIGEN3_INCLUDE_DIR" in os.environ:
        possible_paths.insert(0, Path(os.environ["EIGEN3_INCLUDE_DIR"]))
    
    # Also check parent directory structure
    cwd = Path.cwd()
    parent = cwd.parent
    possible_paths.extend([
        parent / "eigen-3.4.0",
        parent / "eigen",
        cwd / "eigen-3.4.0",
        cwd / "eigen",
    ])
    
    # Look for Eigen/Core header
    for path in possible_paths:
        if path.exists() and (path / "Eigen" / "Core").exists():
            print(f"Found Eigen at: {path.absolute()}", file=sys.stderr)
            return str(path.absolute())
    
    # Try pkg-config as last resort
    try:
        result = subprocess.run(['pkg-config', '--cflags', 'eigen3'], 
                              capture_output=True, text=True)
        if result.returncode == 0:
            include_flag = result.stdout.strip()
            if include_flag.startswith('-I'):
                eigen_path = include_flag[2:]
                print(f"Found Eigen via pkg-config: {eigen_path}", file=sys.stderr)
                return eigen_path
    except:
        pass
    
    # If not found, return the bundled path
    print(f"Warning: Eigen not found in system, using bundled version: eigen-3.4.0", file=sys.stderr)
    return "eigen-3.4.0"

eigen_include = find_eigen()

# Define the extension module
ext_modules = [
    Pybind11Extension(
        "gconcord._gconcord",
        [
            "gconcord/_gconcord.cpp",
            "src/concord_solver.cpp",
            "src/coordinate_descent.cpp", 
            "src/ista_algorithm.cpp",
            "src/symmetric_lasso.cpp",
            "src/concord_utils.cpp",
        ],
        include_dirs=[
            "src/",
            eigen_include,
            pybind11.get_include(),
        ],
        cxx_std=14,
        define_macros=[("VERSION_INFO", '"dev"')],
        extra_compile_args=extra_compile_args,
        extra_link_args=extra_link_args,
    ),
]

setup(
    name="gconcord",
    version="1.0.2",
    author="CONCORD Development Team",
    author_email="support@gconcord.org",
    description="Unified CONCORD Package for Sparse Precision Matrix Estimation",
    long_description=open("README.md").read(),
    long_description_content_type="text/markdown",
    license="MIT",
    url="https://github.com/your-org/gconcord",
    packages=find_packages(),
    package_data={
        "gconcord": ["*.pyi", "py.typed", "*.so", "*.pyd"],
    },
    ext_modules=ext_modules,
    cmdclass={"build_ext": build_ext},
    zip_safe=False,
    python_requires=">=3.7",
    install_requires=[
        "numpy>=1.19.0",
        "scipy>=1.5.0",
    ],
    extras_require={
        "test": ["pytest>=6.0", "pytest-cov"],
        "dev": ["pytest>=6.0", "pytest-cov", "black", "flake8"],
    },
    classifiers=[
        "Development Status :: 4 - Beta",
        "Intended Audience :: Science/Research",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.7",
        "Programming Language :: Python :: 3.8",
        "Programming Language :: Python :: 3.9",
        "Programming Language :: Python :: 3.10",
        "Programming Language :: Python :: 3.11",
        "Topic :: Scientific/Engineering :: Mathematics",
    ],
    keywords="sparse matrices, precision matrix, graphical models, lasso, coordinate descent, ista",
)