from __future__ import annotations

import json
from dataclasses import asdict
from pathlib import Path
from typing import Any, Dict, Optional

from .policy import ProtectMode, parse_mode


def _read_toml(path: Path) -> dict:
    try:
        import tomllib  # py>=3.11
    except Exception:  # pragma: no cover
        import tomli as tomllib  # type: ignore

    return tomllib.loads(path.read_text(encoding="utf-8"))


def load_file_config(path: Optional[str]) -> Dict[str, Any]:
    """
    Load config from:
    - pyproject.toml: [tool.entropic_core]
    - yaml/yml/json: full document object (top-level mapping)
    """
    if not path:
        # Zero-config: if a pyproject.toml exists in the current working directory,
        # load [tool.entropic_core] from it.
        p0 = Path.cwd() / "pyproject.toml"
        if p0.exists():
            try:
                doc = _read_toml(p0)
                tool = doc.get("tool") if isinstance(doc.get("tool"), dict) else {}
                sect = (
                    tool.get("entropic_core") if isinstance(tool.get("entropic_core"), dict) else {}
                )
                return dict(sect) if isinstance(sect, dict) else {}
            except Exception:
                return {}
        return {}

    p = Path(path)
    if not p.exists():
        raise FileNotFoundError(str(p))

    suf = p.suffix.lower().lstrip(".")
    if p.name.lower() == "pyproject.toml" or suf == "toml":
        doc = _read_toml(p)
        tool = doc.get("tool") if isinstance(doc.get("tool"), dict) else {}
        sect = tool.get("entropic_core") if isinstance(tool.get("entropic_core"), dict) else {}
        return dict(sect) if isinstance(sect, dict) else {}

    if suf in {"yaml", "yml"}:
        try:
            import yaml  # type: ignore
        except Exception as e:  # pragma: no cover
            raise RuntimeError(
                "YAML config requires pyyaml. Install with: pip install \"entropic-core[dev]\""
            ) from e
        v = yaml.safe_load(p.read_text(encoding="utf-8"))
        return dict(v) if isinstance(v, dict) else {}

    if suf == "json":
        v = json.loads(p.read_text(encoding="utf-8"))
        return dict(v) if isinstance(v, dict) else {}

    raise ValueError(f"Unsupported config file type: {p}")


def normalize_mode(cfg: Dict[str, Any]) -> ProtectMode:
    v = cfg.get("mode")
    return parse_mode(str(v) if v is not None else None)


def dump_effective_config(
    *,
    mode: ProtectMode,
    middleware_config: Any,
    run_dir: Path,
    extra: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
    # Sanitize non-serializable config fields (e.g., event sinks).
    md = asdict(middleware_config)
    if md.get("event_sink") is not None:
        md["event_sink"] = {"type": type(middleware_config.event_sink).__name__}
    d = {
        "mode": mode.value,
        "run_dir": str(run_dir),
        "middleware": md,
    }
    if extra:
        d["extra"] = dict(extra)
    return d
