"""
Package Resolver - Reads from uv/pyproject.toml instead of duplicating in YAML.

This is the preferred API for package ecosystem queries.

Philosophy:
    packages.yaml should ONLY contain metadata that uv doesn't provide:
    - publication_state (lifecycle)
    - publication_criteria (gates)
    - ci_dependency_resolution (CI rules)
    - consumer import tracking

    Everything else (version, deps, paths) should come from uv/pyproject.toml.

Usage:
    from lightwave.schema.pydantic.sst import PackageResolver

    resolver = PackageResolver()

    # Get version from pyproject.toml (not YAML)
    version = resolver.get_version("lightwave-core")  # Reads pyproject.toml

    # Get CI mode (from YAML publication_state)
    method = resolver.get_ci_mode("lightwave-core")  # "git_clone"

    # Check if publishable (runs uv build --check)
    ready, issues = resolver.check_publish_ready("lightwave-core")
"""

from __future__ import annotations

import subprocess
from functools import lru_cache
from pathlib import Path
from typing import Any

import yaml

try:
    import tomllib  # Python 3.11+
except ImportError:
    import tomli as tomllib  # type: ignore


# =============================================================================
# PATHS
# =============================================================================


def _get_workspace_root() -> Path:
    """Get workspace root (where root pyproject.toml lives)."""
    # Navigate up from this file to find workspace root
    # This file is at: packages/lightwave-core/lightwave/schema/pydantic/sst/packages_v2.py
    # Workspace root is at: lightwave-media/
    current = Path(__file__).resolve().parent  # sst/
    while current != current.parent:
        # Check if this looks like workspace root (has both pyproject.toml and uv.lock)
        if (current / "pyproject.toml").exists() and (current / "uv.lock").exists():
            # Verify it's actually workspace root by checking for workspace config
            with open(current / "pyproject.toml", "rb") as f:
                config = tomllib.load(f)
                if config.get("tool", {}).get("uv", {}).get("workspace"):
                    return current
        current = current.parent
    raise FileNotFoundError("Could not find workspace root with pyproject.toml and uv.lock")


def _get_packages_yaml_path() -> Path:
    """Get path to packages.yaml (from __index.yaml registry)."""
    from lightwave.schema.core.paths import get_sst_path

    return get_sst_path("packages")


# =============================================================================
# UV/PYPROJECT READERS - Get data from uv instead of duplicating
# =============================================================================


@lru_cache(maxsize=1)
def _load_workspace_config() -> dict[str, Any]:
    """Load root pyproject.toml."""
    root = _get_workspace_root()
    with open(root / "pyproject.toml", "rb") as f:
        return tomllib.load(f)


@lru_cache(maxsize=8)
def _load_package_pyproject(package_name: str) -> dict[str, Any]:
    """Load a package's pyproject.toml."""
    root = _get_workspace_root()
    workspace = _load_workspace_config()

    # Find package path from workspace members
    members = workspace.get("tool", {}).get("uv", {}).get("workspace", {}).get("members", [])

    for member in members:
        member_path = root / member / "pyproject.toml"
        if member_path.exists():
            with open(member_path, "rb") as f:
                data = tomllib.load(f)
                if data.get("project", {}).get("name") == package_name:
                    data["_path"] = str(root / member)
                    return data

    raise KeyError(f"Package '{package_name}' not found in workspace members")


def get_version_from_pyproject(package_name: str) -> str:
    """Get package version from pyproject.toml (not YAML)."""
    data = _load_package_pyproject(package_name)
    return data.get("project", {}).get("version", "0.0.0")


def get_local_path_from_workspace(package_name: str) -> str:
    """Get package path from workspace config (not YAML)."""
    data = _load_package_pyproject(package_name)
    return data.get("_path", "")


def get_dependencies_from_pyproject(package_name: str) -> list[str]:
    """Get dependencies from pyproject.toml (not YAML)."""
    data = _load_package_pyproject(package_name)
    return data.get("project", {}).get("dependencies", [])


def get_workspace_members() -> list[str]:
    """Get all workspace member package names."""
    root = _get_workspace_root()
    workspace = _load_workspace_config()
    members = workspace.get("tool", {}).get("uv", {}).get("workspace", {}).get("members", [])

    names = []
    for member in members:
        pyproject_path = root / member / "pyproject.toml"
        if pyproject_path.exists():
            with open(pyproject_path, "rb") as f:
                data = tomllib.load(f)
                name = data.get("project", {}).get("name")
                if name:
                    names.append(name)
    return names


# =============================================================================
# UV COMMANDS - Use uv CLI for operations
# =============================================================================


def run_uv_tree(package_name: str) -> str:
    """Run uv tree for a package."""
    result = subprocess.run(
        ["uv", "tree", "--package", package_name],
        capture_output=True,
        text=True,
        cwd=_get_workspace_root(),
    )
    return result.stdout


def run_uv_build_check(package_path: str) -> tuple[bool, str]:
    """Run uv build --check to verify package builds."""
    result = subprocess.run(
        ["uv", "build", "--check"],
        capture_output=True,
        text=True,
        cwd=package_path,
    )
    return result.returncode == 0, result.stderr


def run_uv_pip_show(package_name: str) -> dict[str, str]:
    """Run uv pip show to get installed package info."""
    result = subprocess.run(
        ["uv", "pip", "show", package_name],
        capture_output=True,
        text=True,
        cwd=_get_workspace_root(),
    )
    info = {}
    for line in result.stdout.strip().split("\n"):
        if ": " in line:
            key, value = line.split(": ", 1)
            info[key.lower().replace("-", "_")] = value
    return info


def check_pypi_version(package_name: str) -> str | None:
    """Check what version is on PyPI."""
    result = subprocess.run(
        ["uv", "pip", "index", "versions", package_name],
        capture_output=True,
        text=True,
    )
    if result.returncode != 0:
        return None
    # Parse output like "Available versions: 0.3.3, 0.3.2, ..."
    if "Available versions:" in result.stdout:
        versions = result.stdout.split("Available versions:")[1].strip()
        return versions.split(",")[0].strip() if versions else None
    return None


# =============================================================================
# PACKAGES.YAML READER - Only for publication state and criteria
# =============================================================================


@lru_cache(maxsize=1)
def _load_packages_yaml() -> dict[str, Any]:
    """Load packages.yaml (only for state/criteria, not versions)."""
    yaml_path = _get_packages_yaml_path()
    if not yaml_path.exists():
        return {}
    with open(yaml_path) as f:
        return yaml.safe_load(f)


def get_publication_state(package_name: str) -> str:
    """Get publication state from YAML (this is what YAML is for).

    v2 YAML format has publication_state at root level of each package,
    not nested in current_state.
    """
    data = _load_packages_yaml()
    pkg = data.get("packages", {}).get(package_name, {})
    # v2 format: publication_state at root level
    return pkg.get("publication_state", "development")


def get_publication_criteria(package_name: str) -> dict[str, Any]:
    """Get publication criteria from YAML."""
    data = _load_packages_yaml()
    pkg = data.get("packages", {}).get(package_name, {})
    return pkg.get("publication_criteria", {})


def get_consumer_imports(package_name: str) -> list[dict[str, Any]]:
    """Get consumer import tracking from YAML."""
    data = _load_packages_yaml()
    pkg = data.get("packages", {}).get(package_name, {})
    return pkg.get("consumers", [])


# =============================================================================
# PACKAGE RESOLVER - Unified API combining uv + YAML
# =============================================================================


class PackageResolver:
    """
    Unified package resolver that:
    - Reads version, path, deps from uv/pyproject.toml
    - Reads publication state, criteria from packages.yaml
    - Uses uv CLI for operations (build, publish checks)
    """

    def get_version(self, package_name: str) -> str:
        """Get version from pyproject.toml."""
        return get_version_from_pyproject(package_name)

    def get_local_path(self, package_name: str) -> str:
        """Get path from workspace config."""
        return get_local_path_from_workspace(package_name)

    def get_dependencies(self, package_name: str) -> list[str]:
        """Get dependencies from pyproject.toml."""
        return get_dependencies_from_pyproject(package_name)

    def get_publication_state(self, package_name: str) -> str:
        """Get publication state from YAML."""
        return get_publication_state(package_name)

    def get_ci_mode(self, package_name: str) -> str:
        """Determine CI install method from publication state."""
        state = self.get_publication_state(package_name)
        if state == "development":
            return "git_clone"
        elif state in ("alpha", "beta"):
            return "pypi_pinned"
        else:
            return "pypi_semver"

    def requires_pat(self, package_name: str) -> bool:
        """Check if CI needs GH_PAT."""
        return self.get_publication_state(package_name) == "development"

    def check_publish_ready(self, package_name: str) -> tuple[bool, list[str]]:
        """
        Check if package is ready to publish.

        Uses combination of:
        - uv build --check (verify it builds)
        - Publication criteria from YAML
        - Version comparison with PyPI
        """
        issues = []

        # 1. Check uv build
        path = self.get_local_path(package_name)
        if path:
            builds, err = run_uv_build_check(path)
            if not builds:
                issues.append(f"Build check failed: {err}")

        # 2. Check YAML publication criteria
        criteria = get_publication_criteria(package_name)
        for name, criterion in criteria.items():
            if criterion.get("blocking") and criterion.get("status") is False:
                issues.append(f"{name}: {criterion.get('description', 'Failed')}")

        # 3. Check version vs PyPI
        local_version = self.get_version(package_name)
        pypi_version = check_pypi_version(package_name)
        if pypi_version and local_version == pypi_version:
            issues.append(f"Version {local_version} already on PyPI - bump version first")

        return len(issues) == 0, issues

    def get_dependency_tree(self, package_name: str) -> str:
        """Get dependency tree from uv tree."""
        return run_uv_tree(package_name)

    def get_all_packages(self) -> list[str]:
        """Get all workspace packages."""
        return get_workspace_members()


# =============================================================================
# MODULE EXPORTS
# =============================================================================

__all__ = [
    "PackageResolver",
    "get_version_from_pyproject",
    "get_local_path_from_workspace",
    "get_dependencies_from_pyproject",
    "get_workspace_members",
    "get_publication_state",
    "get_publication_criteria",
    "get_consumer_imports",
    "run_uv_tree",
    "run_uv_build_check",
    "run_uv_pip_show",
    "check_pypi_version",
]
