"""
Environment-based version resolution for releaseops.

Resolves queries like "support-agent@prod" → BundleManifest at version 2.1.0.
"""

from __future__ import annotations

import logging
from typing import Dict, List, Optional, Tuple

from llmhq_releaseops.models.bundle import BundleManifest
from llmhq_releaseops.models.environment import EnvironmentConfig
from llmhq_releaseops.storage.git_store import GitStore

logger = logging.getLogger(__name__)


class Resolver:
    """
    Resolves bundle versions from environment mappings.

    Core query: "What version of bundle X is in environment Y?"
    """

    def __init__(self, store: GitStore):
        self.store = store

    def resolve(self, bundle_id: str, env: str) -> BundleManifest:
        """
        Resolve a bundle from an environment.

        Args:
            bundle_id: Bundle identifier (e.g., "support-agent")
            env: Environment name (e.g., "prod", "staging", "dev")

        Returns:
            The BundleManifest for the resolved version.

        Raises:
            ValueError: If bundle is not mapped in the environment.
            FileNotFoundError: If the bundle manifest doesn't exist.
        """
        env_config = self.store.load_environment(env)
        version = env_config.get_version(bundle_id)

        if version is None:
            raise ValueError(
                f"Bundle '{bundle_id}' is not mapped in environment '{env}'. "
                f"Available bundles: {env_config.bundle_ids}"
            )

        return self.store.load_bundle(bundle_id, version)

    def resolve_version(self, bundle_id: str, env: str) -> Optional[str]:
        """Get the version of a bundle in an environment (None if not mapped)."""
        try:
            env_config = self.store.load_environment(env)
            return env_config.get_version(bundle_id)
        except FileNotFoundError:
            return None

    def resolve_all(self, env: str) -> Dict[str, str]:
        """Get all bundle mappings for an environment."""
        env_config = self.store.load_environment(env)
        return dict(env_config.bundle_mappings)

    def get_environment(self, env: str) -> EnvironmentConfig:
        """Load an environment configuration."""
        return self.store.load_environment(env)

    def list_environments(self) -> List[str]:
        """List all environment names."""
        return self.store.list_environments()

    def set_version(
        self,
        env: str,
        bundle_id: str,
        version: str,
        updated_by: str = "",
        expected_hash: Optional[str] = None,
    ) -> EnvironmentConfig:
        """
        Directly set a bundle version in an environment (low-level).

        For normal workflows, use Promoter instead — this bypasses gates.

        Args:
            env: Target environment name.
            bundle_id: Bundle identifier.
            version: Version to set.
            updated_by: Who made the change.
            expected_hash: If provided, detect concurrent modification.
        """
        from datetime import datetime, timezone

        from llmhq_releaseops.models.environment import EnvironmentMetadata

        env_config = self.store.load_environment(env)

        # Verify the bundle version exists
        if not self.store.bundle_exists(bundle_id, version):
            raise FileNotFoundError(
                f"Bundle '{bundle_id}' version '{version}' does not exist"
            )

        # Update mapping (need to create new frozen instance)
        new_mappings = dict(env_config.bundle_mappings)
        new_mappings[bundle_id] = version

        updated_env = EnvironmentConfig(
            environment=env_config.environment,
            bundle_mappings=new_mappings,
            promotion_policy=env_config.promotion_policy,
            metadata=EnvironmentMetadata(
                last_updated=datetime.now(timezone.utc).isoformat(),
                updated_by=updated_by,
            ),
        )

        self.store.save_environment(updated_env, expected_hash=expected_hash)
        logger.info(f"Set {bundle_id}={version} in {env}")
        return updated_env
