"""M-24 Fake LLM 클라이언트.

외부 LLM API 호출 없이 미리 정해진 응답을 순환 반환한다.
동기(complete) 및 비동기(complete_async) 인터페이스를 모두 지원한다.

Usage:
    client = FakeLLMClient(responses=["answer1", "answer2"])
    assert client.complete("hello") == "answer1"
    assert client.complete("world") == "answer2"
    assert client.complete("again") == "answer1"  # 순환
"""

from __future__ import annotations

from typing import Any, Coroutine

_DEFAULT_RESPONSE = "fake response"


class FakeLLMClient:
    """미리 설정된 응답을 순환 반환하는 Fake LLM 클라이언트."""

    def __init__(self, responses: list[str] | None = None) -> None:
        """초기화.

        Args:
            responses: 순환 응답 목록. None이면 기본 응답 사용.
        """
        self._responses: list[str] = list(responses) if responses else [_DEFAULT_RESPONSE]
        self._index: int = 0
        self.call_count: int = 0
        self.last_prompt: str | None = None
        self.last_model: str | None = None

    def complete(self, prompt: str, model: str = "fake-model", **kwargs: Any) -> str:
        """다음 응답을 반환한다 (순환).

        Args:
            prompt: 입력 프롬프트.
            model: 모델 이름.
            **kwargs: 추가 파라미터 (무시됨).

        Returns:
            미리 설정된 응답 문자열.
        """
        self.call_count += 1
        self.last_prompt = prompt
        self.last_model = model
        response = self._responses[self._index % len(self._responses)]
        self._index += 1
        return response

    async def _async_complete(self, prompt: str, model: str = "fake-model", **kwargs: Any) -> str:
        """비동기 내부 구현."""
        return self.complete(prompt, model=model, **kwargs)

    def complete_async(self, prompt: str, model: str = "fake-model", **kwargs: Any) -> Coroutine[Any, Any, str]:
        """비동기 버전 — complete()와 동일한 순환 응답.

        Args:
            prompt: 입력 프롬프트.
            model: 모델 이름.
            **kwargs: 추가 파라미터 (무시됨).

        Returns:
            str을 반환하는 코루틴.
        """
        return self._async_complete(prompt, model=model, **kwargs)

    def set_responses(self, responses: list[str]) -> None:
        """응답 목록을 교체하고 인덱스를 초기화한다.

        Args:
            responses: 새로운 응답 목록.
        """
        self._responses = list(responses)
        self._index = 0

    def reset(self) -> None:
        """호출 횟수, 마지막 프롬프트/모델, 인덱스를 초기화한다."""
        self.call_count = 0
        self.last_prompt = None
        self.last_model = None
        self._index = 0
