from contextlib import nullcontext
from datetime import datetime, timezone
from types import SimpleNamespace
from typing import Any
from uuid import UUID, uuid4

from uuid_utils import uuid7

import prodigy_teams.ui as ui
from prodigy_teams.commands import _recipe_subcommand
from prodigy_teams.commands import recipes as recipes_cmd
from prodigy_teams.config import SavedSettings
from prodigy_teams_pam_sdk.models import (
    RecipeListingLatest,
    RecipeSummary,
)


def _uuid7() -> UUID:
    return UUID(str(uuid7()))


def _recipe_summary(
    *,
    name: str,
    job_type: str,
    is_action: bool,
) -> RecipeSummary:
    now = datetime.now(timezone.utc)
    return RecipeSummary(
        id=_uuid7(),
        created=now,
        updated=now,
        org_id=_uuid7(),
        package_id=_uuid7(),
        name=name,
        title=name.title(),
        description="",
        job_type=job_type,
        is_action=is_action,
        is_latest=True,
        entry_point="pkg:recipe",
    )


class _FakeRecipeClient:
    def __init__(self, recipes: list[RecipeSummary]) -> None:
        self._recipes = recipes
        self.calls: list[RecipeListingLatest] = []

    def all_latest(self, *, body: RecipeListingLatest):
        self.calls.append(body)
        return iter(self._recipes)


class _FakePackageClient:
    def all_latest(self, *, body: Any):
        return iter([])


class _FakeAuthState:
    def __init__(self, recipe_client: _FakeRecipeClient) -> None:
        self.client = SimpleNamespace(
            recipe=recipe_client, package=_FakePackageClient()
        )
        self.org_id = uuid4()
        self.broker_id = uuid4()

    def retry(self, fn):
        return fn


def test_request_recipes_accepts_iterator(monkeypatch):
    agent_recipe = _recipe_summary(
        name="agent-recipe", job_type="agent", is_action=False
    )
    task_recipe = _recipe_summary(name="task-recipe", job_type="task", is_action=False)
    recipe_client = _FakeRecipeClient([agent_recipe, task_recipe])
    auth = _FakeAuthState(recipe_client)

    monkeypatch.setattr(_recipe_subcommand, "get_saved_settings", SavedSettings.blank)
    monkeypatch.setattr(ui, "loading", lambda *_args, **_kwargs: nullcontext())

    schemas = _recipe_subcommand.request_recipes(auth=auth, job_type="agent")  # type: ignore[arg-type]

    assert list(schemas) == ["agent-recipe"]
    assert recipe_client.calls == [
        RecipeListingLatest(org_id=auth.org_id, broker_id=auth.broker_id)
    ]


def test_recipes_list_accepts_iterator(monkeypatch):
    first = _recipe_summary(name="alpha", job_type="task", is_action=False)
    second = _recipe_summary(name="beta", job_type="action", is_action=True)
    recipe_client = _FakeRecipeClient([first, second])
    auth = _FakeAuthState(recipe_client)
    captured: dict[str, Any] = {}

    monkeypatch.setattr(recipes_cmd, "get_auth_state", lambda: auth)
    monkeypatch.setattr(
        recipes_cmd,
        "print_table_with_select",
        lambda items, *, select, as_json: captured.update(
            items=list(items),
            select=select,
            as_json=as_json,
        ),
    )

    items = recipes_cmd.list()

    assert [item["name"] for item in items] == ["alpha", "beta"]
    assert [item["name"] for item in captured["items"]] == ["alpha", "beta"]
    assert recipe_client.calls == [
        RecipeListingLatest(org_id=auth.org_id, broker_id=auth.broker_id)
    ]
