"""Pathway Loader — directory scanning and YAML->Pathway parsing.

Loads pathway definitions from filesystem directories.
"""

from __future__ import annotations

import logging
import os
from pathlib import Path
from typing import Any

import yaml

from core.common import JsonObject
from core.pathways.models.node_spec import parse_node_spec
from core.pathways.models.pathway_spec import parse_pathway_spec
from core.pathways.pathway import Pathway
from core.pathways.registry import PathwayMeta, PathwayRegistry

logger = logging.getLogger(__name__)


def node_from_dict(node_dict: JsonObject | dict[str, Any]) -> Any:
    """Create a typed node from a dictionary."""
    return parse_node_spec(node_dict)


def pathway_from_dict(data: JsonObject | dict[str, Any]) -> Pathway:
    """Create a Pathway from a dictionary using Pydantic models.

    Uses typed PathwaySpec model for validation and conversion.
    """
    spec = parse_pathway_spec(data)
    return spec.to_pathway()


async def load_from_directory(
    directory: str | Path,
    registry: PathwayRegistry,
    *,
    source: str = "directory",
    recursive: bool = True,
) -> list[PathwayMeta]:
    """Load all pathway YAML files from a directory.

    Args:
        directory: Directory path to scan for .yaml/.yml files
        registry: PathwayRegistry to register loaded pathways into
        source: Source identifier for loaded pathways
        recursive: Whether to scan subdirectories

    Returns
    -------
        List of PathwayMeta for successfully loaded pathways
    """
    directory = Path(os.path.expanduser(os.path.expandvars(str(directory))))

    if not directory.exists():
        logger.warning("Pathway directory does not exist: %s", directory)
        return []

    if not directory.is_dir():
        logger.warning("Path is not a directory: %s", directory)
        return []

    pattern = "**/*.yaml" if recursive else "*.yaml"
    yaml_files = list(directory.glob(pattern))

    yml_pattern = "**/*.yml" if recursive else "*.yml"
    yaml_files.extend(directory.glob(yml_pattern))

    loaded: list[PathwayMeta] = []

    for yaml_file in sorted(yaml_files):
        try:
            with open(yaml_file) as f:
                data = yaml.safe_load(f)

            if not data:
                continue

            if not isinstance(data, dict):
                continue
            if not data.get("nodes") and not data.get("id"):
                continue

            if not data.get("id"):
                rel_path = yaml_file.relative_to(directory)
                data["id"] = str(rel_path.with_suffix("")).replace("/", ".").replace("\\", ".")

            pathway = pathway_from_dict(data)

            file_source = f"{source}:{yaml_file.relative_to(directory)}"

            meta = registry.deploy(
                pathway,
                source=file_source,
            )
            loaded.append(meta)
            logger.debug("Loaded pathway from %s: %s", yaml_file.name, pathway.id)

        except Exception as e:
            logger.warning("Failed to load pathway from %s: %s", yaml_file, e)
            continue

    if loaded:
        logger.info("Loaded %d pathways from %s", len(loaded), directory)

    return loaded


async def load_from_directories(
    directories: list[str],
    registry: PathwayRegistry,
    *,
    source: str = "config",
) -> int:
    """Load pathways from multiple directories.

    Args:
        directories: List of directory paths
        registry: PathwayRegistry to register into
        source: Source identifier prefix

    Returns
    -------
        Total number of pathways loaded
    """
    total = 0

    for dir_path in directories:
        try:
            loaded = await load_from_directory(
                dir_path,
                registry,
                source=source,
            )
            total += len(loaded)
        except Exception as e:
            logger.exception("Failed to load pathways from %s: %s", dir_path, e)

    return total


__all__ = [
    "load_from_directories",
    "load_from_directory",
    "node_from_dict",
    "pathway_from_dict",
]
