"""Resource bundle resolution and materialization utilities."""

from __future__ import annotations

import os
import uuid
from pathlib import Path
from typing import Any


def resolve_entry(
    entry: str | dict[str, Any],
    resource_type: str = "",
    sandbox_dir: str | None = None,
) -> tuple[str, str | None, str | None]:
    """Resolve a str or dict entry to (name, resolved_path, sandbox_dir).

    If ``entry`` is a ``str``, returns ``(entry, None, sandbox_dir)``.

    If ``entry`` is a dict resource bundle (has ``name`` and ``resources``),
    materializes it via :func:`materialize_bundle` and returns
    ``(name, materialized_path, updated_sandbox_dir)``.

    Otherwise extracts the name from the dict and returns
    ``(name, None, sandbox_dir)``.

    Args:
        entry: A string name/path, or a dict (inline tool dict or resource bundle).
        resource_type: Type hint (``"tool"``, ``"agent"``, ``"skill"``).
        sandbox_dir: Current sandbox directory (may be ``None``).

    Returns:
        Tuple of ``(name, resolved_path_or_None, sandbox_dir)``.
    """
    if isinstance(entry, str):
        return entry, None, sandbox_dir

    if not isinstance(entry, dict):
        return str(entry), None, sandbox_dir

    # Resource bundle (has "name" and "resources") → materialize
    if "name" in entry and "resources" in entry:
        materialized_path, sandbox_dir = materialize_bundle(
            entry,
            sandbox_dir,
        )
        return entry["name"], materialized_path, sandbox_dir

    # Not a resource bundle — return as-is (e.g. inline tool dict)
    name = (
        entry.get("name")
        or entry.get("function", {}).get("name")
        or str(id(entry))
    )
    return name, None, sandbox_dir


def materialize_bundle(
    bundle: dict[str, Any],
    sandbox_dir: str | None,
) -> tuple[str, str]:
    """Materialize a resource bundle to the session sandbox.

    Creates the directory tree from ``bundle["structure"]`` and writes
    all files from ``bundle["resources"]``.

    Args:
        bundle: Resource bundle dict with ``name``, ``type``, ``resources``,
            ``structure`` keys.
        sandbox_dir: Session sandbox directory. If None, a new session
            directory is created under ``FLUXIBLY_SANDBOX_DIR`` (env var,
            default ``/tmp/fluxibly/``).

    Returns:
        Tuple of (materialized_path, sandbox_dir). The sandbox_dir is
        returned so the caller can store it if it was newly created.
    """
    name = bundle["name"]
    res_type = bundle.get("type", "tool")
    resources = bundle.get("resources", {})
    structure = bundle.get("structure", {})

    # Determine sandbox dir
    if not sandbox_dir:
        sandbox_root = os.environ.get("FLUXIBLY_SANDBOX_DIR", "/tmp/fluxibly/")
        sandbox_dir = str(Path(sandbox_root) / str(uuid.uuid4()))

    # Target directory: <sandbox>/resources/<type>s/<name>/
    type_dir_name = f"{res_type}s"  # "tools", "agents", "skills"
    target_dir = Path(sandbox_dir) / "resources" / type_dir_name / name
    target_dir.mkdir(parents=True, exist_ok=True)

    # Create directory tree from structure
    _create_dir_tree(target_dir, structure)

    # Write all files
    config_path: Path | None = None
    for relative_path, content in resources.items():
        file_path = target_dir / relative_path
        file_path.parent.mkdir(parents=True, exist_ok=True)
        file_path.write_text(content)
        # Track config.yaml for the return path
        if relative_path in ("config.yaml", "config.yml"):
            config_path = file_path

    # Return path to config file if found, otherwise the directory
    if config_path:
        return str(config_path), sandbox_dir
    # Fallback: look for any .yaml file
    yaml_files = list(target_dir.glob("*.yaml")) + list(
        target_dir.glob("*.yml")
    )
    if yaml_files:
        return str(yaml_files[0]), sandbox_dir
    return str(target_dir), sandbox_dir


def _create_dir_tree(root: Path, structure: dict[str, Any]) -> None:
    """Recursively create directories from a structure descriptor."""
    for key, value in structure.items():
        if isinstance(value, dict):
            subdir = root / key
            subdir.mkdir(parents=True, exist_ok=True)
            _create_dir_tree(subdir, value)
        # "file" entries don't need mkdir — handled by materialize_bundle
