"""
Package Ecosystem Pydantic Schemas (v2).

Type-safe models for package lifecycle management, CI dependency resolution,
and version alignment across the LightWave ecosystem. Validated against
schema/definitions/packages.yaml at runtime.

v2 Design Philosophy:
    - Version, path, dependencies are read from pyproject.toml via uv (not duplicated)
    - This schema ONLY contains metadata uv doesn't provide:
      - publication_state (lifecycle stage)
      - publication_criteria (gates before publishing)
      - ci_dependency_resolution (CI rules)
      - consumer import tracking

Usage:
    from lightwave.schema.pydantic.models.packages import (
        PackagesConfig,
        PackageEcosystemSchema,
        PackageDefinition,
    )

    # Load entire ecosystem
    config = PackageEcosystemSchema.load()

    # Get CI install method for a package
    method = config.get_ci_mode("lightwave-core")  # "git_clone"

    # Check if package requires PAT
    pkg = config.get_package("lightwave-core")
    requires_pat = pkg.requires_pat()  # True (because development)
"""

from __future__ import annotations

from functools import lru_cache
from pathlib import Path
from typing import Any, ClassVar, Literal

import yaml
from pydantic import Field, field_validator

from lightwave.schema.pydantic.core.base import SSTSchema

# =============================================================================
# LITERAL TYPES
# =============================================================================

# Publication lifecycle states
PublicationState = Literal["development", "alpha", "beta", "stable", "deprecated"]

# CI install methods (determines pip behavior)
CIInstallMethod = Literal[
    "git_clone",  # Clone repo + pip install -e (requires PAT)
    "workspace_clone",  # Clone repo within workspace
    "pypi_pinned",  # pip install package==version
    "pypi_compatible",  # pip install package~=version
    "pypi_semver",  # pip install package>=version,<next_major
]

# API stability level
StabilityLevel = Literal["unstable", "stabilizing", "stable"]

# How consumer declares dependency
DependencyInstallMethod = Literal["workspace", "pypi", "git_clone"]

# Publication criterion status (can be bool or "in_progress")
CriterionStatus = bool | Literal["in_progress"]


# =============================================================================
# VALID VALUES FROM YAML
# =============================================================================

VALID_PUBLICATION_STATES: set[str] = {
    "development",
    "alpha",
    "beta",
    "stable",
    "deprecated",
}

VALID_CI_INSTALL_METHODS: set[str] = {
    "git_clone",
    "workspace_clone",
    "pypi_pinned",
    "pypi_compatible",
    "pypi_semver",
}

VALID_STABILITY_LEVELS: set[str] = {"unstable", "stabilizing", "stable"}

VALID_DEPENDENCY_INSTALL_METHODS: set[str] = {"workspace", "pypi", "git_clone"}


# =============================================================================
# YAML CONFIGURATION LOADER
# =============================================================================


def _get_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")


@lru_cache(maxsize=1)
def _load_packages_yaml() -> dict[str, Any]:
    """Load and cache packages.yaml."""
    yaml_path = _get_yaml_path()
    if not yaml_path.exists():
        return {
            "publication_states": {"definitions": {}},
            "packages": {},
            "ci_dependency_resolution": {"rules": [], "decision_tree": {}, "error_conditions": {}},
            "version_alignment": {"checks": []},
            "publishing_workflow": {"phases": {}},
            "cli_commands": {"commands": {}},
            "incident_record": {},
        }
    with open(yaml_path) as f:
        return yaml.safe_load(f)


class PackagesConfig:
    """
    Runtime configuration loaded from packages.yaml.

    Provides type-safe access to YAML-defined values with caching.
    """

    @classmethod
    def _yaml(cls) -> dict[str, Any]:
        """Get cached YAML data."""
        return _load_packages_yaml()

    # -------------------------------------------------------------------------
    # PUBLICATION STATES
    # -------------------------------------------------------------------------

    @classmethod
    def get_publication_states(cls) -> list[str]:
        """Get all valid publication state values."""
        states = cls._yaml().get("publication_states", {}).get("definitions", {})
        return list(states.keys())

    @classmethod
    def is_valid_publication_state(cls, state: str) -> bool:
        """Check if a publication state is valid."""
        return state in cls.get_publication_states()

    @classmethod
    def get_publication_state_config(cls, state: str) -> dict[str, Any]:
        """Get configuration for a publication state."""
        states = cls._yaml().get("publication_states", {}).get("definitions", {})
        return states.get(state, {})

    @classmethod
    def is_pypi_available(cls, state: str) -> bool:
        """Check if PyPI is available for this publication state."""
        config = cls.get_publication_state_config(state)
        return config.get("pypi_available", False)

    @classmethod
    def get_ci_install_method_for_state(cls, state: str) -> str:
        """Get CI install method for a publication state."""
        config = cls.get_publication_state_config(state)
        return config.get("ci_install_method", "git_clone")

    @classmethod
    def requires_pat_for_state(cls, state: str) -> bool:
        """Check if state requires PAT for CI."""
        config = cls.get_publication_state_config(state)
        return config.get("requires_pat", True)

    # -------------------------------------------------------------------------
    # PACKAGES
    # -------------------------------------------------------------------------

    @classmethod
    def get_package_names(cls) -> list[str]:
        """Get all package names."""
        packages = cls._yaml().get("packages", {})
        return list(packages.keys())

    @classmethod
    def get_package_config(cls, name: str) -> dict[str, Any]:
        """Get configuration for a package."""
        packages = cls._yaml().get("packages", {})
        return packages.get(name, {})

    @classmethod
    def get_package_publication_state(cls, name: str) -> str | None:
        """Get publication state for a package (v2: at root level)."""
        config = cls.get_package_config(name)
        return config.get("publication_state")

    # -------------------------------------------------------------------------
    # CI DEPENDENCY RESOLUTION
    # -------------------------------------------------------------------------

    @classmethod
    def get_ci_resolution_rules(cls) -> list[dict[str, Any]]:
        """Get CI dependency resolution rules."""
        resolution = cls._yaml().get("ci_dependency_resolution", {})
        return resolution.get("rules", [])

    @classmethod
    def get_ci_decision_tree(cls) -> dict[str, str]:
        """Get CI decision tree steps."""
        resolution = cls._yaml().get("ci_dependency_resolution", {})
        return resolution.get("decision_tree", {}).get("steps", {})

    # -------------------------------------------------------------------------
    # VERSION ALIGNMENT
    # -------------------------------------------------------------------------

    @classmethod
    def get_version_alignment_checks(cls) -> list[dict[str, Any]]:
        """Get version alignment checks."""
        alignment = cls._yaml().get("version_alignment", {})
        return alignment.get("checks", [])

    # -------------------------------------------------------------------------
    # CACHE MANAGEMENT
    # -------------------------------------------------------------------------

    @classmethod
    def clear_cache(cls) -> None:
        """Clear the YAML cache (for testing)."""
        _load_packages_yaml.cache_clear()


# =============================================================================
# PUBLICATION STATE DEFINITION
# =============================================================================


class PublicationStateDefinition(SSTSchema):
    """
    Defines behavior for each publication state.

    Attributes:
        description: Human-readable description
        pypi_available: Whether package is on PyPI
        ci_install_method: How CI should install
        requires_pat: Whether CI needs GH_PAT
        stability: API stability level
        consumers_should: Advice for consumers
        version_pattern: Expected version pattern
    """

    description: str = Field(..., description="Human-readable description")
    pypi_available: bool = Field(..., description="Whether package is on PyPI")
    ci_install_method: str = Field(..., description="How CI should install")
    requires_pat: bool = Field(True, description="Whether CI needs GH_PAT")
    stability: str = Field(..., description="API stability level")
    consumers_should: str = Field(..., description="Advice for consumers")
    version_pattern: str | None = Field(None, description="Expected version pattern")

    @field_validator("ci_install_method")
    @classmethod
    def validate_ci_install_method(cls, v: str) -> str:
        """Validate CI install method."""
        if v not in VALID_CI_INSTALL_METHODS:
            raise ValueError(f"Invalid CI install method '{v}'. Valid: {VALID_CI_INSTALL_METHODS}")
        return v

    @field_validator("stability")
    @classmethod
    def validate_stability(cls, v: str) -> str:
        """Validate stability level."""
        if v not in VALID_STABILITY_LEVELS:
            raise ValueError(f"Invalid stability level '{v}'. Valid: {VALID_STABILITY_LEVELS}")
        return v


# =============================================================================
# PACKAGE CURRENT STATE (Legacy - for backward compatibility)
# =============================================================================


class PackageCurrentState(SSTSchema):
    """
    Snapshot of package's current publication status.

    NOTE: This is kept for backward compatibility. v2 YAML uses
    publication_state at root level.

    Attributes:
        publication_state: Current lifecycle state
        version: Last published version (may be stale)
        local_version: Version in development
        last_published: ISO date of last publish
        pypi_url: URL on PyPI
    """

    publication_state: str = Field(..., description="Current lifecycle state")
    version: str | None = Field(None, description="Last published version")
    local_version: str | None = Field(None, description="Version in development")
    last_published: str | None = Field(None, description="ISO date of last publish")
    pypi_url: str | None = Field(None, description="URL on PyPI")

    @field_validator("publication_state")
    @classmethod
    def validate_publication_state(cls, v: str) -> str:
        """Validate publication state."""
        if v not in VALID_PUBLICATION_STATES:
            raise ValueError(f"Invalid publication state '{v}'. Valid: {VALID_PUBLICATION_STATES}")
        return v


# =============================================================================
# CONSUMER IMPORT CONFIG
# =============================================================================


class ConsumerImportConfig(SSTSchema):
    """
    Tracks what a consumer package imports.

    Attributes:
        package: Consumer package name
        imports: Module paths imported
        version_requirement: PEP 440 version spec
    """

    package: str = Field(..., description="Consumer package name")
    imports: list[str] = Field(default_factory=list, description="Module paths imported")
    version_requirement: str = Field(..., description="PEP 440 version spec")

    @field_validator("version_requirement")
    @classmethod
    def validate_version_spec(cls, v: str) -> str:
        """Validate PEP 440 version specifier."""
        try:
            from packaging.specifiers import SpecifierSet

            SpecifierSet(v)
        except ImportError:
            # packaging not available, skip validation
            pass
        except Exception as e:
            raise ValueError(f"Invalid version specifier: {v}") from e
        return v


# =============================================================================
# PUBLICATION CRITERION
# =============================================================================


class PublicationCriterion(SSTSchema):
    """
    Single criterion that must pass before publishing.

    Attributes:
        description: What this criterion checks
        status: Current status (bool or "in_progress")
        blocking: Whether this blocks publication
        validation: Command to check (optional)
    """

    description: str = Field(..., description="What this criterion checks")
    status: bool | str = Field(..., description="Current status")
    blocking: bool = Field(True, description="Whether this blocks publication")
    validation: str | None = Field(None, description="Command to check")

    @field_validator("status")
    @classmethod
    def validate_status(cls, v: bool | str) -> bool | str:
        """Validate status is bool or 'in_progress'."""
        if isinstance(v, bool):
            return v
        if v == "in_progress":
            return v
        raise ValueError(f"Invalid status '{v}'. Must be bool or 'in_progress'")


# =============================================================================
# DEPENDENCY CONFIG
# =============================================================================


class DependencyConfig(SSTSchema):
    """
    How a package declares a dependency.

    Attributes:
        requirement: Version requirement (e.g., ">=0.4.0")
        install_method: How to install (workspace/pypi/git_clone)
        fallback_method: Fallback if primary fails
    """

    requirement: str = Field(..., description="Version requirement")
    install_method: str = Field(..., description="How to install")
    fallback_method: str | None = Field(None, description="Fallback if primary fails")

    @field_validator("install_method")
    @classmethod
    def validate_install_method(cls, v: str) -> str:
        """Validate install method."""
        if v not in VALID_DEPENDENCY_INSTALL_METHODS:
            raise ValueError(f"Invalid install method '{v}'. Valid: {VALID_DEPENDENCY_INSTALL_METHODS}")
        return v

    @field_validator("fallback_method")
    @classmethod
    def validate_fallback_method(cls, v: str | None) -> str | None:
        """Validate fallback method if provided."""
        if v is not None and v not in VALID_DEPENDENCY_INSTALL_METHODS:
            raise ValueError(f"Invalid fallback method '{v}'. Valid: {VALID_DEPENDENCY_INSTALL_METHODS}")
        return v


# =============================================================================
# CI CONFIG
# =============================================================================


class CIConfig(SSTSchema):
    """
    CI configuration for a package.

    Attributes:
        test_command: Command to run tests
        requires_services: Services needed (e.g., postgres, redis)
    """

    test_command: str = Field(..., description="Command to run tests")
    requires_services: list[str] = Field(default_factory=list, description="Services needed")


# =============================================================================
# PACKAGE DEFINITION (v2)
# =============================================================================


class PackageDefinition(SSTSchema):
    """
    Complete definition of a package in the ecosystem (v2).

    v2 Design Philosophy:
        - Version, path, dependencies are read from pyproject.toml via uv
        - This schema ONLY contains metadata uv doesn't provide:
          - publication_state (lifecycle stage)
          - publication_criteria (gates before publishing)
          - consumers (import tracking)
          - provides (module exports)

    Attributes:
        publication_state: Current lifecycle state (v2: at root level)
        publication_criteria: Gates for publication
        consumers: Packages that depend on this
        provides: Module paths this package provides
        is_deployable: Whether this is deployed (not published to PyPI)
        package_manager: npm for JS packages, default is uv/pip
        ci: CI configuration
    """

    SST_FILE: ClassVar[str] = "packages.yaml"
    SST_KEY: ClassVar[str] = "packages"

    # Publication state (v2: at root level, not nested)
    publication_state: str = Field(..., description="Current lifecycle state")

    # Publication gates
    publication_criteria: dict[str, PublicationCriterion] | None = Field(None, description="Publication criteria")

    # Consumer tracking (uv doesn't provide this)
    consumers: list[ConsumerImportConfig] | None = Field(None, description="Dependent packages")

    # Module exports (for import validation)
    provides: list[str] | None = Field(None, description="Module paths provided")

    # For deployable packages (not published to PyPI)
    is_deployable: bool | None = Field(None, description="Whether deployed as container")

    # For non-Python packages
    package_manager: str | None = Field(None, description="npm for JS packages")

    # CI config
    ci: CIConfig | None = Field(None, description="CI configuration")

    @field_validator("publication_state")
    @classmethod
    def validate_publication_state(cls, v: str) -> str:
        """Validate publication state."""
        if v not in VALID_PUBLICATION_STATES:
            raise ValueError(f"Invalid publication state '{v}'. Valid: {VALID_PUBLICATION_STATES}")
        return v

    def get_ci_install_method(self) -> str:
        """
        Determine how CI should install this package.

        Returns:
            CI install method based on publication state
        """
        state = self.publication_state
        if state == "development":
            return "git_clone"
        elif state in ("alpha", "beta"):
            return "pypi_pinned"
        else:
            return "pypi_semver"

    def requires_pat(self) -> bool:
        """
        Check if CI needs GH_PAT to install this package.

        Returns:
            True if package is in development state
        """
        return self.publication_state == "development"

    def is_publishable(self) -> tuple[bool, list[str]]:
        """
        Check if package meets all blocking publication criteria.

        Returns:
            Tuple of (is_publishable, list of blocking issues)
        """
        if not self.publication_criteria:
            return True, []

        blockers = []
        for name, criterion in self.publication_criteria.items():
            if criterion.blocking and criterion.status is False:
                blockers.append(f"{name}: {criterion.description}")

        return len(blockers) == 0, blockers


# =============================================================================
# CI RESOLUTION MODELS
# =============================================================================


class CIRequirement(SSTSchema):
    """
    Secret or resource required for CI.

    Attributes:
        secret: Secret name
        description: What it's for
    """

    secret: str = Field(..., description="Secret name")
    description: str = Field(..., description="What it's for")


class CIWhenCondition(SSTSchema):
    """
    Condition for CI rule matching.

    Attributes:
        publication_state: State(s) to match
    """

    publication_state: str | list[str] = Field(..., description="State(s) to match")


class CIThenAction(SSTSchema):
    """
    Action to take when condition matches.

    Attributes:
        method: CI install method
        requires: Required secrets
        install_command: Command to run
        version_source: Where to get version
    """

    method: str = Field(..., description="CI install method")
    requires: list[CIRequirement] | list[dict[str, str]] = Field(default_factory=list, description="Required secrets")
    install_command: str = Field(..., description="Command to run")
    version_source: str | None = Field(None, description="Where to get version")


class CIResolutionRule(SSTSchema):
    """
    Single CI dependency resolution rule.

    Attributes:
        when: Condition for this rule
        then: Action to take
    """

    when: CIWhenCondition = Field(..., description="Condition for this rule")
    then: CIThenAction = Field(..., description="Action to take")


class ErrorCondition(SSTSchema):
    """
    Known error and resolution.

    Attributes:
        description: What the error is
        detection: How to detect it
        resolution: How to fix it
    """

    description: str = Field(..., description="What the error is")
    detection: str = Field(..., description="How to detect it")
    resolution: str = Field(..., description="How to fix it")


class CIDecisionTree(SSTSchema):
    """
    CI decision tree for dependency resolution.

    Attributes:
        description: What this tree does
        steps: Numbered steps
    """

    description: str = Field(..., description="What this tree does")
    steps: dict[int, str] | dict[str, str] = Field(default_factory=dict, description="Numbered steps")


class CIDependencyResolution(SSTSchema):
    """
    Complete CI dependency resolution configuration.

    Attributes:
        description: What this does
        rules: Resolution rules
        decision_tree: Decision steps
        error_conditions: Known errors
    """

    description: str = Field(..., description="What this does")
    rules: list[CIResolutionRule] = Field(default_factory=list, description="Resolution rules")
    decision_tree: CIDecisionTree | None = Field(None, description="Decision steps")
    error_conditions: dict[str, ErrorCondition] = Field(default_factory=dict, description="Known errors")

    def get_install_method(self, state: str) -> CIThenAction:
        """
        Find the appropriate action for a publication state.

        Args:
            state: Publication state to match

        Returns:
            CIThenAction for the matched rule

        Raises:
            ValueError: If no rule matches
        """
        for rule in self.rules:
            condition = rule.when.publication_state
            if isinstance(condition, list):
                if state in condition:
                    return rule.then
            elif state == condition:
                return rule.then
        raise ValueError(f"No CI rule for state: {state}")


# =============================================================================
# VERSION ALIGNMENT
# =============================================================================


class VersionAlignmentCheck(SSTSchema):
    """
    Single version alignment check.

    Attributes:
        name: Check name
        description: What this checks (optional)
        provider: Provider package
        consumer: Consumer package
        validation: Validation logic
    """

    name: str = Field(..., description="Check name")
    description: str | None = Field(None, description="What this checks")
    provider: str | None = Field(None, description="Provider package")
    consumer: str | None = Field(None, description="Consumer package")
    validation: str | None = Field(None, description="Validation logic")


class VersionAlignment(SSTSchema):
    """
    Version alignment configuration.

    Attributes:
        description: What this does
        checks: Alignment checks
        validation_commands: Commands for validation
    """

    description: str = Field(..., description="What this does")
    checks: list[VersionAlignmentCheck] = Field(default_factory=list, description="Alignment checks")
    validation_commands: dict[str, str] | None = Field(None, description="Validation commands")


# =============================================================================
# PUBLISHING WORKFLOW
# =============================================================================


class PublishingPhase(SSTSchema):
    """
    Single phase in publishing workflow.

    Attributes:
        name: Phase name
        steps: Steps in this phase
    """

    name: str = Field(..., description="Phase name")
    steps: list[str] = Field(default_factory=list, description="Steps in this phase")


class PublishingWorkflow(SSTSchema):
    """
    Complete publishing workflow.

    Attributes:
        description: What this does
        phases: Workflow phases
    """

    description: str = Field(..., description="What this does")
    phases: dict[str, PublishingPhase] = Field(default_factory=dict, description="Workflow phases")


# =============================================================================
# CLI COMMANDS
# =============================================================================


class CLICommandSpec(SSTSchema):
    """
    CLI command specification.

    Attributes:
        description: What this command does
    """

    description: str = Field(..., description="What this command does")


class CLICommandsRegistry(SSTSchema):
    """
    CLI commands registry.

    Attributes:
        description: What this section does
        source_of_truth: Where commands are defined
        commands: Command specifications
    """

    description: str = Field(..., description="What this section does")
    source_of_truth: str | None = Field(None, description="Where commands are defined")
    commands: dict[str, CLICommandSpec] = Field(default_factory=dict, description="Command specs")


# =============================================================================
# INCIDENT RECORD
# =============================================================================


class IncidentRecord(SSTSchema):
    """
    Record of incident that created this schema.

    Attributes:
        date: When it happened
        description: What happened
        root_cause: Why it happened
        resolution: How it was fixed
        prevention: How to prevent recurrence
    """

    date: str = Field(..., description="When it happened")
    description: str = Field(..., description="What happened")
    root_cause: list[str] = Field(default_factory=list, description="Why it happened")
    resolution: list[str] = Field(default_factory=list, description="How it was fixed")
    prevention: list[str] = Field(default_factory=list, description="How to prevent recurrence")


# =============================================================================
# PUBLICATION STATES CONTAINER
# =============================================================================


class PublicationStatesContainer(SSTSchema):
    """
    Container for publication state definitions.

    Attributes:
        description: What this section does
        definitions: State definitions
    """

    description: str = Field(..., description="What this section does")
    definitions: dict[str, PublicationStateDefinition] = Field(default_factory=dict, description="State definitions")


# =============================================================================
# ROOT SCHEMA
# =============================================================================


class PackageEcosystemSchema(SSTSchema):
    """
    Root schema for entire packages.yaml (v2).

    This is the main entry point for loading and validating the package
    ecosystem configuration.

    Usage:
        config = PackageEcosystemSchema.load()
        method = config.get_ci_mode("lightwave-core")
        pkg = config.get_package("lightwave-core")
    """

    SST_FILE: ClassVar[str] = "packages.yaml"

    publication_states: PublicationStatesContainer = Field(..., description="Publication state definitions")
    packages: dict[str, PackageDefinition] = Field(..., description="Package definitions")
    ci_dependency_resolution: CIDependencyResolution = Field(..., description="CI resolution config")
    version_alignment: VersionAlignment = Field(..., description="Version alignment config")
    publishing_workflow: PublishingWorkflow = Field(..., description="Publishing workflow")
    cli_commands: CLICommandsRegistry = Field(..., description="CLI commands registry")
    incident_record: IncidentRecord = Field(..., description="Incident record")

    @classmethod
    def load(cls) -> "PackageEcosystemSchema":
        """
        Load and validate packages.yaml.

        Returns:
            Validated PackageEcosystemSchema instance
        """
        data = _load_packages_yaml()
        # Remove _meta before validation
        data = dict(data)  # Copy to avoid modifying cache
        data.pop("_meta", None)

        # Parse packages into PackageDefinition objects
        packages_raw = data.get("packages", {})
        parsed_packages: dict[str, Any] = {}

        for pkg_name, pkg_data in packages_raw.items():
            if isinstance(pkg_data, dict):
                # Parse nested objects
                if "consumers" in pkg_data and pkg_data["consumers"]:
                    consumers = []
                    for consumer in pkg_data["consumers"]:
                        if isinstance(consumer, dict):
                            consumers.append(ConsumerImportConfig(**consumer))
                    pkg_data["consumers"] = consumers

                if "publication_criteria" in pkg_data and pkg_data["publication_criteria"]:
                    criteria = {}
                    for crit_name, crit_config in pkg_data["publication_criteria"].items():
                        if isinstance(crit_config, dict):
                            criteria[crit_name] = PublicationCriterion(**crit_config)
                    pkg_data["publication_criteria"] = criteria

                if "ci" in pkg_data and pkg_data["ci"] and isinstance(pkg_data["ci"], dict):
                    pkg_data["ci"] = CIConfig(**pkg_data["ci"])

                parsed_packages[pkg_name] = PackageDefinition(**pkg_data)
            else:
                # Skip non-dict values (like description strings)
                pass

        data["packages"] = parsed_packages
        return cls.model_validate(data)

    def get_package(self, name: str) -> PackageDefinition:
        """
        Get typed package definition.

        Args:
            name: Package name (e.g., "lightwave-core")

        Returns:
            PackageDefinition instance

        Raises:
            KeyError: If package not found
        """
        if name not in self.packages:
            raise KeyError(f"Package '{name}' not found in packages.yaml")
        return self.packages[name]

    def get_package_names(self) -> list[str]:
        """
        Get all package names.

        Returns:
            List of package names
        """
        return list(self.packages.keys())

    def get_ci_mode(self, package_name: str) -> str:
        """
        Get CI install method for a package.

        Args:
            package_name: Package name

        Returns:
            CI install method string
        """
        pkg = self.get_package(package_name)
        return pkg.get_ci_install_method()

    def validate_alignment(self) -> list[str]:
        """
        Check all consumer/provider version alignment.

        Returns:
            List of alignment errors (empty if all aligned)
        """
        errors = []

        for _pkg_name, pkg in self.packages.items():
            if not pkg.consumers:
                continue

            for _consumer in pkg.consumers:
                # Development packages should use workspace, not PyPI
                if pkg.publication_state == "development":
                    pass  # Skip PyPI version checks for development packages

        return errors


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

__all__ = [
    # Literal types
    "PublicationState",
    "CIInstallMethod",
    "StabilityLevel",
    "DependencyInstallMethod",
    "CriterionStatus",
    # Configuration
    "PackagesConfig",
    # Publication state
    "PublicationStateDefinition",
    "PublicationStatesContainer",
    # Package state and config
    "PackageCurrentState",
    "ConsumerImportConfig",
    "PublicationCriterion",
    "DependencyConfig",
    "CIConfig",
    "PackageDefinition",
    # CI Resolution
    "CIRequirement",
    "CIWhenCondition",
    "CIThenAction",
    "CIResolutionRule",
    "ErrorCondition",
    "CIDecisionTree",
    "CIDependencyResolution",
    # Version alignment
    "VersionAlignmentCheck",
    "VersionAlignment",
    # Publishing
    "PublishingPhase",
    "PublishingWorkflow",
    # CLI
    "CLICommandSpec",
    "CLICommandsRegistry",
    # Incident
    "IncidentRecord",
    # Root schema
    "PackageEcosystemSchema",
]
