"""One LLM call classifies discovered links as product-detail pages or not
-- the fallback for sites whose URLs don't match the regex heuristic. Must
never raise: a prioritization hint failing must not break the crawl."""
import json
from unittest.mock import MagicMock, patch

import pytest

from app.services.content import website


def _llm_returning(payload):
    response = MagicMock()
    response.choices = [MagicMock()]
    response.choices[0].message.content = json.dumps(payload)
    response.usage = MagicMock(prompt_tokens=10, completion_tokens=5, total_tokens=15)
    return response


CANDIDATES = [
    ("https://shop.example.com/sku/12345", "Oxford Shirt"),
    ("https://shop.example.com/browse/shirts", "Shop Shirts"),
]


@pytest.mark.asyncio
async def test_classifies_by_index_into_urls():
    with patch.object(website, "openai_client") as client:
        client.chat.completions.create.return_value = _llm_returning({"product_indices": [0]})
        result = await website._classify_product_links(CANDIDATES, "org_x")

    assert result == {"https://shop.example.com/sku/12345"}


@pytest.mark.asyncio
async def test_empty_verdict_is_an_empty_set():
    with patch.object(website, "openai_client") as client:
        client.chat.completions.create.return_value = _llm_returning({"product_indices": []})
        result = await website._classify_product_links(CANDIDATES, "org_x")

    assert result == set()


@pytest.mark.asyncio
async def test_llm_failure_returns_empty_set_not_an_exception():
    with patch.object(website, "openai_client") as client:
        client.chat.completions.create.side_effect = RuntimeError("timeout")
        result = await website._classify_product_links(CANDIDATES, "org_x")

    assert result == set()


@pytest.mark.asyncio
async def test_malformed_json_returns_empty_set_not_an_exception():
    with patch.object(website, "openai_client") as client:
        response = MagicMock()
        response.choices = [MagicMock()]
        response.choices[0].message.content = "not json"
        client.chat.completions.create.return_value = response
        result = await website._classify_product_links(CANDIDATES, "org_x")

    assert result == set()


@pytest.mark.asyncio
async def test_out_of_range_index_is_ignored_not_a_crash():
    with patch.object(website, "openai_client") as client:
        client.chat.completions.create.return_value = _llm_returning({"product_indices": [0, 99]})
        result = await website._classify_product_links(CANDIDATES, "org_x")

    assert result == {"https://shop.example.com/sku/12345"}


@pytest.mark.asyncio
async def test_non_dict_json_payload_returns_empty_set_not_an_exception():
    with patch.object(website, "openai_client") as client:
        response = MagicMock()
        response.choices = [MagicMock()]
        # Valid JSON, but the top level is an array, not an object -- a
        # payload.get(...) call on this would raise AttributeError.
        response.choices[0].message.content = "[0, 3]"
        response.usage = MagicMock(prompt_tokens=10, completion_tokens=5, total_tokens=15)
        client.chat.completions.create.return_value = response
        result = await website._classify_product_links(CANDIDATES, "org_x")

    assert result == set()
