"""Deterministic provider for tests and local development without API keys.
Responses are queued per schema name; a callable may compute a response from the request."""
from __future__ import annotations
import json
from collections import defaultdict, deque
from typing import Any, Callable

from pydantic import ValidationError

from .base import ProviderError, Result, SchemaError


class FakeProvider:
    name = "fake"

    def __init__(self):
        self.queue: dict[str, deque] = defaultdict(deque)
        self.calls: list[dict] = []

    def push(self, schema_name: str, response: dict | Callable[[dict], dict] | Exception) -> None:
        self.queue[schema_name].append(response)

    def structured(self, *, model, system, parts, schema, max_tokens=8000, cache_system=True) -> Result:
        call = {"model": model, "system": system, "parts": parts, "schema": schema.__name__}
        self.calls.append(call)
        q = self.queue[schema.__name__]
        if not q:
            raise ProviderError(f"FakeProvider: no response queued for {schema.__name__}", retryable=False)
        item: Any = q.popleft()
        if isinstance(item, Exception):
            raise item
        data = item(call) if callable(item) else item
        raw = json.dumps(data, ensure_ascii=False)
        try:
            parsed = schema.model_validate(data)
        except ValidationError as e:
            raise SchemaError(str(e), raw) from e
        text_len = sum(len(getattr(p, "text", "")) for p in parts)
        return Result(parsed=parsed, raw_text=raw, provider=self.name, model=model,
                      tokens_in=len(system) // 4 + text_len // 4 + 1000, tokens_out=len(raw) // 4)
