import os
import sys
import json
import hashlib
import warnings
from pathlib import Path
from typing import Optional

from .exceptions import (
    CppApiError,
    CppBuildError,
    CppModuleNotFoundError,
    CppModuleOutdatedError,
    CppReloadWarning,
    CppValidationError
)
from ..cli.config_parser import CppProjectConfig

class CppApi:
    def __init__(self, verbose: bool = False, auto_update: bool = False, config_path: Optional[Path] = None):
        """Initialize C++ API.

        Args:
            verbose: Enable detailed logging
            auto_update: Auto-rebuild outdated modules on include()
            config_path: Path to cpp.proj (defaults to cwd/cpp.proj)
        """
        self.project_root = Path.cwd()
        self.config = CppProjectConfig(config_path or (self.project_root / "cpp.proj"))
        self.base_dir = self.config.base_dir
        self.registry_file = self.base_dir / ".module_registry.json"
        self.bindings_dir = self.base_dir / "bindings"

        self.verbose = verbose
        self.auto_update = auto_update
        self.silent = False

        if str(self.bindings_dir) not in sys.path:
            sys.path.insert(0, str(self.bindings_dir))

        self.registry = self._load_registry()
        self.api_module = None
        self._import_api()

    def _load_registry(self):
        if not self.registry_file.exists():
            if self.verbose:
                print(f"[WARNING] Registry file not found: {self.registry_file}")
                print(f"[INFO] Run 'python -m includecpp rebuild' in project directory")
            return {}

        try:
            with open(self.registry_file, 'r') as f:
                return json.load(f)
        except Exception as e:
            if self.verbose:
                print(f"[WARNING] Failed to load registry: {e}")
            return {}

    def _save_registry(self):
        try:
            with open(self.registry_file, 'w') as f:
                json.dump(self.registry, f, indent=2)
        except Exception:
            pass

    def _import_api(self):
        try:
            if 'api' in sys.modules:
                self.api_module = sys.modules['api']
            else:
                import api
                self.api_module = api
        except ImportError:
            if self.verbose:
                print(f"[WARNING] api module not found in {self.bindings_dir}")
                print(f"[INFO] Run 'python -m includecpp rebuild' to build C++ modules")
            self.api_module = None

    def _compute_hash(self, filepath):
        if not os.path.exists(filepath):
            return "0"

        try:
            with open(filepath, 'rb') as f:
                return hashlib.sha256(f.read()).hexdigest()
        except Exception:
            return "0"

    def exists(self, module_name):
        if module_name not in self.registry:
            return False

        if self.api_module is None:
            return False

        try:
            return hasattr(self.api_module, module_name)
        except Exception:
            return False

    def include(self, module_name: str, auto_update: Optional[bool] = None):
        """Load a C++ module.

        Args:
            module_name: Name of module to load
            auto_update: Override instance auto_update setting (None = use instance setting)

        Returns:
            Module object

        Raises:
            CppModuleNotFoundError: If module not found in registry
        """
        if module_name not in self.registry:
            raise CppModuleNotFoundError(
                f"Module '{module_name}' not registered.\n"
                f"Available modules: {list(self.registry.keys())}\n"
                f"Run 'python -m includecpp rebuild' to build modules."
            )

        if not self.exists(module_name):
            raise CppModuleNotFoundError(
                f"Module '{module_name}' in registry but not in api module.\n"
                f"Run 'python -m includecpp rebuild' to rebuild."
            )

        try:
            return getattr(self.api_module, module_name)
        except AttributeError:
            raise CppModuleNotFoundError(
                f"Module '{module_name}' not found in api module."
            )

    def noFeedback(self):
        """Disable all warnings and feedback messages."""
        self.silent = True

    def list_modules(self):
        return list(self.registry.keys())

    def get_module_info(self, module_name):
        if module_name not in self.registry:
            return None

        return self.registry[module_name]
