import copy
import pytest

from app.services.beer_pairing.config import BeerPairingServiceConfig
from app.services.beer_pairing.models.requests import (
    BeerPairingRequest,
    BeerPairingFood,
    BeerCardItem,
)
from app.services.beer_pairing.service import BeerPairingService
from app.services.beer_pairing import service as service_module


class DeterministicRng:
    def randint(self, a, b):
        return a  # deterministic seed

    def shuffle(self, seq):
        return seq

    def sample(self, population, k):
        return list(population[:k])


@pytest.mark.anyio("asyncio")
async def test_match_beers_includes_user_prompt(monkeypatch):
    captured_prompt = {}

    async def fake_json_completion(*, api_key, model, prompt, operation_id, service, **kwargs):
        captured_prompt["value"] = prompt
        fake_response = {
            "language": "en",
            "results": [
                {
                    "food": "Seared Salmon",
                    "matches": [
                        {
                            "beer": "Sunset Pale",
                            "reason": "Bright acidity lifts the salmon.",
                            "beer_rating": "Unknown",
                            "price": "Unknown",
                        }
                    ],
                    "suggestions": [],
                    "notes": "Focus on refreshing rosé picks.",
                }
            ],
        }
        fake_metrics = {
            "input_tokens": 1,
            "output_tokens": 1,
            "cost": 0.0,
            "model": model,
        }
        return fake_response, fake_metrics

    monkeypatch.setattr(service_module.openai_client, "json_completion", fake_json_completion)

    config = BeerPairingServiceConfig(
        enabled=True,
        openai_api_key="test-key",
        beer_pairing_model="gpt-test",
        untappd_lookup_model="gpt-test",
        untappd_lookup_enabled=False,
    )
    service = BeerPairingService(config)

    request = BeerPairingRequest(
        language="en",
        foods=[BeerPairingFood(name="Seared Salmon")],
        beers=[BeerCardItem(name="Sunset Rosé", price="$40")],
        user_prompt="add 3 more beers with citrus notes",
    )

    await service.match_beers(request)

    assert "add 3 more beers with citrus notes" in captured_prompt["value"]
    assert "Additional diner instructions" in captured_prompt["value"]


@pytest.mark.anyio("asyncio")
async def test_match_beers_holds_extra_matches_with_user_prompt(monkeypatch):
    template_response = {
        "language": "en",
        "results": [
            {
                "food": "Steak",
                "matches": [
                    {"beer": "Beer A", "reason": "R1", "beer_rating": "Unknown", "price": "Unknown"},
                    {"beer": "Beer B", "reason": "R2", "beer_rating": "Unknown", "price": "Unknown"},
                    {"beer": "Beer C", "reason": "R3", "beer_rating": "Unknown", "price": "Unknown"},
                    {"beer": "Beer D", "reason": "R4", "beer_rating": "Unknown", "price": "Unknown"},
                ],
                "suggestions": [],
                "notes": "Standard notes.",
            }
        ],
    }

    async def fake_json_completion(**kwargs):
        return copy.deepcopy(template_response), {
            "input_tokens": 1,
            "output_tokens": 1,
            "cost": 0.0,
            "model": kwargs["model"],
        }

    monkeypatch.setattr(service_module.openai_client, "json_completion", fake_json_completion)

    config = BeerPairingServiceConfig(
        enabled=True,
        openai_api_key="test-key",
        beer_pairing_model="gpt-test",
        untappd_lookup_model="gpt-test",
        untappd_lookup_enabled=False,
    )
    service = BeerPairingService(config)
    service._rng = DeterministicRng()

    with_prompt = BeerPairingRequest(
        language="en",
        foods=[BeerPairingFood(name="Steak")],
        beers=[BeerCardItem(name="Beer A")],
        user_prompt="add 3 more beer suggestions",
    )
    without_prompt = BeerPairingRequest(
        language="en",
        foods=[BeerPairingFood(name="Steak")],
        beers=[BeerCardItem(name="Beer A")],
    )

    result_with_prompt = await service.match_beers(with_prompt)
    result_without_prompt = await service.match_beers(without_prompt)

    matches_with_prompt = result_with_prompt["results"][0]["matches"]
    matches_without_prompt = result_without_prompt["results"][0]["matches"]

    assert len(matches_with_prompt) == 4
    assert len(matches_without_prompt) == 2
