"""Business logic for the provisioning engine.

Coordinates fixture registration, seed execution, snapshot management,
and benchmark generation. Used by management commands and programmatic APIs.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from simorgh.apps.provisioning.providers import (
    DjangoModelProvider,
    FixtureProvider,
    ProviderResult,
)
from simorgh.apps.provisioning.resolver import DependencyResolver
from simorgh.apps.provisioning.runners import ResetRunner, SeedRunner

if TYPE_CHECKING:
    from simorgh.apps.provisioning.snapshot import SnapshotManager


class ProvisioningService:
    """Central service for all provisioning operations.

    Coordinates fixture registration, seed/reset execution, snapshot
    management, and benchmark generation.
    """

    def __init__(self) -> None:
        self._registry: dict[str, FixtureProvider] = {}

    def register(self, provider: FixtureProvider) -> None:
        """Register a fixture provider for later execution."""
        if provider.name in self._registry:
            raise ValueError(f"Provider {provider.name!r} already registered")
        self._registry[provider.name] = provider

    def register_bulk(self, providers: list[FixtureProvider]) -> None:
        for p in providers:
            self.register(p)

    def get_provider(self, name: str) -> FixtureProvider:
        if name not in self._registry:
            raise KeyError(f"Provider {name!r} not registered")
        return self._registry[name]

    def list_providers(
        self,
        tag: str | None = None,
        scope: str | None = None,
    ) -> list[FixtureProvider]:
        """List registered providers, optionally filtered by tag or scope."""
        providers = list(self._registry.values())
        if tag:
            providers = [p for p in providers if tag in p.tags]
        if scope:
            providers = [p for p in providers if p.scope == scope]
        return providers

    def create_seed_runner(
        self,
        names: list[str] | None = None,
        batch_atomic: bool = True,
    ) -> SeedRunner:
        """Create a SeedRunner pre-populated with selected (or all) providers."""
        runner = SeedRunner(batch_atomic=batch_atomic)
        providers = (
            [self._registry[n] for n in names]
            if names
            else list(self._registry.values())
        )
        runner.register_bulk(providers)
        return runner

    def create_reset_runner(
        self,
        names: list[str] | None = None,
    ) -> ResetRunner:
        """Create a ResetRunner pre-populated with selected (or all) providers."""
        runner = ResetRunner()
        providers = (
            [self._registry[n] for n in names]
            if names
            else list(self._registry.values())
        )
        runner.register_bulk(providers)
        return runner

    def seed(
        self,
        context: dict[str, Any] | None = None,
        names: list[str] | None = None,
        *,
        dry_run: bool = False,
    ) -> list[ProviderResult]:
        """Execute seed for selected (or all) providers."""
        runner = self.create_seed_runner(names=names)
        return runner.run(context=context, dry_run=dry_run)

    def reset(
        self,
        context: dict[str, Any] | None = None,
        names: list[str] | None = None,
        *,
        dry_run: bool = False,
    ) -> list[ProviderResult]:
        """Execute reset for selected (or all) providers."""
        runner = self.create_reset_runner(names=names)
        return runner.run(context=context, dry_run=dry_run)

    def create_snapshot_manager(self, storage_dir: Any = None) -> SnapshotManager:
        from simorgh.apps.provisioning.snapshot import SnapshotManager

        return SnapshotManager(storage_dir=storage_dir)

    def create_model_provider(
        self,
        name: str,
        model: str,
        data: list[dict[str, Any]],
        unique_fields: tuple[str, ...] = ("id",),
        depends_on: tuple[str, ...] = (),
    ) -> DjangoModelProvider:
        """Convenience factory for DjangoModelProvider."""
        provider = DjangoModelProvider(
            name=name,
            model_class=model,
            data=data,
            unique_fields=unique_fields,
            depends_on=depends_on,
        )
        self.register(provider)
        return provider

    def resolve_order(self, names: list[str] | None = None) -> list[str]:
        """Return the topological execution order for given (or all) providers."""
        resolver = DependencyResolver()
        providers = (
            [self._registry[n] for n in names]
            if names
            else list(self._registry.values())
        )
        resolver.register_bulk(providers)
        return resolver.resolve_names()

    def reset_registry(self) -> None:
        self._registry.clear()
