"""
Configuration loader for AMI tool registration.

Supports two config file formats:
1. `.ami/config.yaml` - Explicit YAML config file
2. `pyproject.toml [tool.ami]` - Standard Python project config

Precedence (highest to lowest):
1. Explicit function arguments
2. .ami/config.yaml
3. pyproject.toml [tool.ami]
4. Environment variables (AMI_WORKSPACE, AMI_PROJECT, etc.)

Example .ami/config.yaml:
    tools:
      entry: myproject.agent.tools.handlers
      schema_path: .ami/tools_schema.json

    platform:
      workspace: development
      project: my-pipeline

Example pyproject.toml:
    [tool.ami]
    tools_entry = "myproject.agent.tools.handlers"
    schema_path = ".ami/tools_schema.json"
    workspace = "development"
    project = "my-pipeline"
"""

import os
from dataclasses import dataclass, field
from pathlib import Path
from typing import Optional

import yaml

# tomllib is in stdlib for Python 3.11+, fallback to tomli for older versions
try:
    import tomllib
except ImportError:
    try:
        import tomli as tomllib  # type: ignore
    except ImportError:
        tomllib = None  # type: ignore


class ToolConfigError(Exception):
    """Raised when tool configuration is invalid or incomplete."""

    pass


@dataclass
class AMIToolConfig:
    """
    Configuration for AMI tool registration.

    Attributes:
        tools_entry: Python module path to import (triggers @tool registration).
                     e.g., "myproject.agent.tools.handlers"
        schema_path: Local file path for tool schema. Default: ".ami/tools_schema.json"
        workspace: Platform workspace slug or ID.
        project: Platform project slug or ID.
        api_url: API base URL. Falls back to AMI_BASE_URL or AMI_API_URL env vars.
        org_id: Organization slug or ID. Falls back to AMI_ORG or AMI_ORG_ID env vars.
        project_root: Root directory of the project (where config was found).
    """

    tools_entry: Optional[str] = None
    schema_path: str = ".ami/tools_schema.json"
    workspace: Optional[str] = None
    project: Optional[str] = None
    api_url: Optional[str] = None
    org_id: Optional[str] = None
    project_root: Optional[Path] = field(default=None, repr=False)

    def require_tools_entry(self) -> str:
        """Return tools_entry or raise error if not configured."""
        if not self.tools_entry:
            raise ToolConfigError(
                "tools_entry is required but not configured. "
                "Set in .ami/config.yaml (tools.entry) or pyproject.toml ([tool.ami] tools_entry)."
            )
        return self.tools_entry

    def require_workspace(self) -> str:
        """Return workspace or raise error if not configured."""
        if not self.workspace:
            raise ToolConfigError(
                "workspace is required but not configured. "
                "Set in config file or AMI_WORKSPACE environment variable."
            )
        return self.workspace

    def require_project(self) -> str:
        """Return project or raise error if not configured."""
        if not self.project:
            raise ToolConfigError(
                "project is required but not configured. "
                "Set in config file or AMI_PROJECT environment variable."
            )
        return self.project

    def resolve_schema_path(self) -> Path:
        """Resolve schema_path relative to project_root."""
        schema = Path(self.schema_path)
        if schema.is_absolute():
            return schema
        if self.project_root:
            return self.project_root / schema
        return Path.cwd() / schema


def find_project_root(start_dir: Optional[Path] = None) -> Optional[Path]:
    """
    Find project root by walking up from start_dir.

    Looks for (in order):
    1. .ami/ directory
    2. pyproject.toml file

    Args:
        start_dir: Directory to start searching from. Defaults to cwd.

    Returns:
        Path to project root, or None if not found.
    """
    current = Path(start_dir) if start_dir else Path.cwd()
    current = current.resolve()

    # Walk up the directory tree
    while current != current.parent:
        # Check for .ami directory
        if (current / ".ami").is_dir():
            return current
        # Check for pyproject.toml
        if (current / "pyproject.toml").is_file():
            return current
        current = current.parent

    # Check root as well
    if (current / ".ami").is_dir() or (current / "pyproject.toml").is_file():
        return current

    return None


def _load_yaml_config(config_path: Path) -> dict:
    """Load config from .ami/config.yaml file."""
    try:
        with open(config_path) as f:
            data = yaml.safe_load(f) or {}
        return data
    except FileNotFoundError:
        return {}
    except yaml.YAMLError as e:
        raise ToolConfigError(f"Invalid YAML in {config_path}: {e}")


def _load_toml_config(pyproject_path: Path) -> dict:
    """Load [tool.ami] section from pyproject.toml."""
    if tomllib is None:
        # Can't parse TOML without tomllib/tomli
        return {}

    try:
        with open(pyproject_path, "rb") as f:
            data = tomllib.load(f)
        return data.get("tool", {}).get("ami", {})
    except FileNotFoundError:
        return {}
    except Exception as e:
        raise ToolConfigError(f"Invalid TOML in {pyproject_path}: {e}")


def _merge_env_vars(config: dict) -> dict:
    """Merge environment variables into config (lower priority than file config)."""
    env_mappings = {
        "workspace": ["AMI_WORKSPACE", "AMI_WORKSPACE_ID"],
        "project": ["AMI_PROJECT", "AMI_PROJECT_ID"],
        "api_url": ["AMI_BASE_URL", "AMI_API_URL"],
        "org_id": ["AMI_ORG", "AMI_ORG_ID"],
    }

    result = dict(config)
    for key, env_names in env_mappings.items():
        if key not in result or result[key] is None:
            for env_name in env_names:
                value = os.getenv(env_name)
                if value:
                    result[key] = value
                    break

    return result


def load_config(
    project_root: Optional[Path] = None,
    *,
    tools_entry: Optional[str] = None,
    schema_path: Optional[str] = None,
    workspace: Optional[str] = None,
    project: Optional[str] = None,
    api_url: Optional[str] = None,
    org_id: Optional[str] = None,
) -> AMIToolConfig:
    """
    Load AMI tool configuration with auto-detection and precedence handling.

    Precedence (highest to lowest):
    1. Explicit function arguments
    2. .ami/config.yaml
    3. pyproject.toml [tool.ami]
    4. Environment variables

    Args:
        project_root: Root directory to search for config. Auto-detected if None.
        tools_entry: Override tools_entry from config.
        schema_path: Override schema_path from config.
        workspace: Override workspace from config.
        project: Override project from config.
        api_url: Override api_url from config.
        org_id: Override org_id from config.

    Returns:
        AMIToolConfig instance with merged configuration.

    Raises:
        ToolConfigError: If config files are invalid.
    """
    # Find project root if not provided
    root = Path(project_root) if project_root else find_project_root()

    # Start with empty config
    merged: dict = {}

    if root:
        # Load pyproject.toml first (lower priority)
        pyproject_path = root / "pyproject.toml"
        if pyproject_path.exists():
            toml_config = _load_toml_config(pyproject_path)
            merged.update(toml_config)

        # Load .ami/config.yaml (higher priority, overrides pyproject.toml)
        yaml_path = root / ".ami" / "config.yaml"
        if yaml_path.exists():
            yaml_config = _load_yaml_config(yaml_path)

            # Handle nested structure in YAML
            if "tools" in yaml_config:
                tools_section = yaml_config["tools"]
                if "entry" in tools_section:
                    merged["tools_entry"] = tools_section["entry"]
                if "schema_path" in tools_section:
                    merged["schema_path"] = tools_section["schema_path"]

            if "platform" in yaml_config:
                platform_section = yaml_config["platform"]
                merged.update(platform_section)

            # Also support flat keys in YAML
            for key in ["tools_entry", "schema_path", "workspace", "project", "api_url", "org_id"]:
                if key in yaml_config:
                    merged[key] = yaml_config[key]

    # Merge environment variables (lower priority than file config)
    merged = _merge_env_vars(merged)

    # Apply explicit arguments (highest priority)
    if tools_entry is not None:
        merged["tools_entry"] = tools_entry
    if schema_path is not None:
        merged["schema_path"] = schema_path
    if workspace is not None:
        merged["workspace"] = workspace
    if project is not None:
        merged["project"] = project
    if api_url is not None:
        merged["api_url"] = api_url
    if org_id is not None:
        merged["org_id"] = org_id

    return AMIToolConfig(
        tools_entry=merged.get("tools_entry"),
        schema_path=merged.get("schema_path", ".ami/tools_schema.json"),
        workspace=merged.get("workspace"),
        project=merged.get("project"),
        api_url=merged.get("api_url"),
        org_id=merged.get("org_id"),
        project_root=root,
    )
