"""Genus-to-family taxonomy lookup using bundled IOC data."""

from __future__ import annotations

import json
from pathlib import Path

import structlog

logger = structlog.get_logger()

_TAXONOMY: dict[str, str] | None = None
_CACHE_PATH: Path | None = None
_WARNED_GENERA: set[str] = set()


def _load_bundled() -> dict[str, str]:
    """Load the bundled taxonomy mapping from package data.

    Handles both the new format ({"genera": {...}, "species": {...}})
    and the old flat format ({"Genus": "Family"}).
    """
    data_path = Path(__file__).parent.parent / "data" / "taxonomy.json"
    if not data_path.exists():
        return {}
    with open(data_path) as f:
        data = json.load(f)

    # New format: extract genus->family from "genera" key
    if "genera" in data:
        return {genus: info["family"] for genus, info in data["genera"].items() if info.get("family")}

    # Old flat format: already genus->family
    return data


def _load_cache(data_dir: Path) -> dict[str, str]:
    """Load the user's taxonomy cache (may contain updated/additional entries)."""
    cache = data_dir / "taxonomy-cache.json"
    if cache.exists():
        with open(cache) as f:
            return json.load(f)
    return {}


def _save_cache(data_dir: Path, taxonomy: dict[str, str]) -> None:
    """Save the taxonomy cache."""
    cache = data_dir / "taxonomy-cache.json"
    cache.parent.mkdir(parents=True, exist_ok=True)
    with open(cache, "w") as f:
        json.dump(taxonomy, f, indent=2, sort_keys=True)


def init_taxonomy(data_dir: Path | None = None) -> dict[str, str]:
    """Initialise the taxonomy lookup, merging bundled data with user cache."""
    global _TAXONOMY, _CACHE_PATH

    bundled = _load_bundled()
    user_cache: dict[str, str] = {}
    if data_dir:
        _CACHE_PATH = data_dir
        user_cache = _load_cache(data_dir)

    # User cache overrides bundled data
    _TAXONOMY = {**bundled, **user_cache}
    logger.debug("taxonomy_loaded", genera=len(_TAXONOMY))
    return _TAXONOMY


def lookup_family(genus: str, data_dir: Path | None = None) -> str:
    """Look up the family for a given genus. Returns 'Unknown_Family' if not found."""
    global _TAXONOMY
    if _TAXONOMY is None:
        init_taxonomy(data_dir)

    assert _TAXONOMY is not None
    family = _TAXONOMY.get(genus)
    if family:
        return family

    # Try case-insensitive
    genus_lower = genus.lower()
    for g, f in _TAXONOMY.items():
        if g.lower() == genus_lower:
            return f

    if genus not in _WARNED_GENERA:
        _WARNED_GENERA.add(genus)
        logger.warning("unknown_genus", genus=genus)
    return "Unknown_Family"


def add_to_cache(genus: str, family: str, data_dir: Path | None = None) -> None:
    """Add a genus-family mapping to the user cache."""
    global _TAXONOMY
    if _TAXONOMY is None:
        init_taxonomy(data_dir)
    assert _TAXONOMY is not None

    _TAXONOMY[genus] = family
    if data_dir or _CACHE_PATH:
        _save_cache(data_dir or _CACHE_PATH, _TAXONOMY)  # type: ignore[arg-type]
