import base64

from rights_filter.analysis.preprocessing import ImagePayload
from rights_filter.domain.records import Evidence, EvidenceSource
from rights_filter.integrations.cloud_vision_web_detection import GoogleVisionRestClient
from rights_filter.integrations.env_clients import build_provider_runtime
from rights_filter.integrations.google_custom_search import GoogleCustomSearchClient
from rights_filter.integrations.naver_search import NaverOpenApiSearchClient
from rights_filter.analysis.llm_assistance import OllamaGenerateLlmClient


class FakeJsonTransport:
    def __init__(self, response):
        self.response = response
        self.calls = []

    def request_json(self, method, url, headers=None, payload=None, timeout=10):
        self.calls.append(
            {
                "method": method,
                "url": url,
                "headers": headers or {},
                "payload": payload,
                "timeout": timeout,
            }
        )
        return self.response


def test_naver_open_api_client_uses_env_headers_and_text_query():
    transport = FakeJsonTransport({"items": [{"title": "IU", "link": "https://image"}]})
    client = NaverOpenApiSearchClient(
        client_id="naver-id",
        client_secret="naver-secret",
        transport=transport,
    )

    response = client.search_image("IU album cover")

    call = transport.calls[0]
    assert response["items"][0]["title"] == "IU"
    assert call["method"] == "GET"
    assert call["url"].startswith("https://openapi.naver.com/v1/search/image?")
    assert "query=IU+album+cover" in call["url"]
    assert call["headers"]["X-Naver-Client-Id"] == "naver-id"
    assert call["headers"]["X-Naver-Client-Secret"] == "naver-secret"


def test_google_vision_rest_client_sends_web_detection_request_with_api_key():
    transport = FakeJsonTransport(
        {
            "responses": [
                {
                    "webDetection": {
                        "webEntities": [{"description": "IU", "score": 0.91}],
                        "fullMatchingImages": [{"url": "https://image"}],
                        "pagesWithMatchingImages": [{"url": "https://page"}],
                        "bestGuessLabels": [{"label": "IU photo"}],
                    }
                }
            ]
        }
    )
    client = GoogleVisionRestClient(api_key="google-key", transport=transport)

    response = client.detect_web(ImagePayload(b"image-bytes", 100, 100, {}))

    call = transport.calls[0]
    assert call["method"] == "POST"
    assert call["url"] == "https://vision.googleapis.com/v1/images:annotate?key=google-key"
    assert call["payload"]["requests"][0]["features"][0]["type"] == "WEB_DETECTION"
    assert call["payload"]["requests"][0]["image"]["content"] == base64.b64encode(b"image-bytes").decode("ascii")
    assert response["web_entities"][0]["description"] == "IU"
    assert response["full_matching_images"][0]["url"] == "https://image"


def test_google_vision_rest_client_preserves_all_image_search_result_types():
    transport = FakeJsonTransport(
        {
            "responses": [
                {
                    "webDetection": {
                        "partialMatchingImages": [{"url": "https://partial", "score": 0.7}],
                        "visuallySimilarImages": [{"url": "https://similar", "score": 0.5}],
                        "pagesWithMatchingImages": [
                            {
                                "url": "https://page",
                                "score": 0.8,
                                "pageTitle": "Known celebrity page",
                                "fullMatchingImages": [{"url": "https://page/full.jpg"}],
                                "partialMatchingImages": [{"url": "https://page/partial.jpg"}],
                            }
                        ],
                    }
                }
            ]
        }
    )
    client = GoogleVisionRestClient(api_key="google-key", transport=transport)

    response = client.detect_web(ImagePayload(b"image-bytes", 100, 100, {}))

    assert response["partial_matching_images"][0] == {"url": "https://partial", "score": 0.7}
    assert response["visually_similar_images"][0] == {"url": "https://similar", "score": 0.5}
    assert response["pages_with_matching_images"][0]["page_title"] == "Known celebrity page"
    assert response["pages_with_matching_images"][0]["page_image_urls"] == [
        "https://page/full.jpg",
        "https://page/partial.jpg",
    ]


def test_google_custom_search_client_uses_env_key_and_search_engine_id():
    transport = FakeJsonTransport({"items": []})
    client = GoogleCustomSearchClient(
        api_key="google-search-key",
        cx="search-engine-id",
        transport=transport,
    )

    client.search_image("IU official profile")

    call = transport.calls[0]
    assert call["method"] == "GET"
    assert call["url"].startswith("https://www.googleapis.com/customsearch/v1?")
    assert "key=google-search-key" in call["url"]
    assert "cx=search-engine-id" in call["url"]
    assert "q=IU+official+profile" in call["url"]
    assert "searchType=image" in call["url"]


def test_ollama_generate_client_uses_local_endpoint_and_returns_response_text():
    transport = FakeJsonTransport({"response": "Source-linked summary"})
    client = OllamaGenerateLlmClient(
        base_url="http://localhost:11434",
        model="qwen2.5:0.5b-instruct",
        transport=transport,
    )
    evidence = [
        Evidence(
            source=EvidenceSource.NAVER_SEARCH,
            reason="Naver search result found",
            confidence=0.8,
            data={"title": "IU", "result_url": "https://source"},
        )
    ]

    summary = client.summarize_evidence(evidence)

    call = transport.calls[0]
    assert summary == "Source-linked summary"
    assert call["method"] == "POST"
    assert call["url"] == "http://localhost:11434/api/generate"
    assert call["headers"] == {}
    assert call["payload"]["model"] == "qwen2.5:0.5b-instruct"
    assert call["payload"]["stream"] is False
    assert "source evidence" in call["payload"]["prompt"].lower()
    assert "source evidence" in call["payload"]["system"].lower()


def test_provider_runtime_wires_clients_from_environment():
    env = {
        "NAVER_CLIENT_ID": "naver-id",
        "NAVER_CLIENT_SECRET": "naver-secret",
        "GOOGLE_CLOUD_VISION_API_KEY": "google-key",
        "GOOGLE_CUSTOM_SEARCH_API_KEY": "google-search-key",
        "GOOGLE_CUSTOM_SEARCH_CX": "search-engine-id",
        "OLLAMA_BASE_URL": "http://localhost:11434",
        "OLLAMA_MODEL": "qwen2.5:0.5b-instruct",
    }

    runtime = build_provider_runtime(env=env, transport=FakeJsonTransport({}))

    assert runtime.naver_adapter is not None
    assert runtime.google_adapter is not None
    assert runtime.google_custom_search_adapter is not None
    assert runtime.llm_assistant is not None
    assert runtime.provider_payloads["naver"]["enabled"] is True
    assert runtime.provider_payloads["google"]["enabled"] is True
    assert runtime.provider_payloads["google_search"]["enabled"] is True
    assert runtime.provider_payloads["llm"]["enabled"] is True
    assert runtime.provider_payloads["google_search"]["requiredEnv"] == [
        "GOOGLE_CUSTOM_SEARCH_API_KEY",
        "GOOGLE_CUSTOM_SEARCH_CX",
    ]
    assert runtime.provider_payloads["google_search"]["configuredEnv"] == {
        "GOOGLE_CUSTOM_SEARCH_API_KEY": True,
        "GOOGLE_CUSTOM_SEARCH_CX": True,
    }
    assert runtime.auto_naver_query_limit == 3
    assert runtime.auto_naver_blog_query_limit == 1
    assert runtime.auto_naver_web_query_limit == 1
    assert runtime.auto_google_custom_query_limit == 2
    assert runtime.search_result_compare_limit == 3
    assert runtime.search_result_page_image_limit == 3
    assert runtime.search_result_similarity_threshold == 0.9


def test_provider_runtime_wires_search_pagination_limits_from_environment():
    runtime = build_provider_runtime(
        env={
            "NAVER_CLIENT_ID": "naver-id",
            "NAVER_CLIENT_SECRET": "naver-secret",
            "NAVER_SEARCH_PAGES": "2",
            "NAVER_BLOG_SEARCH_PAGES": "3",
            "NAVER_WEB_SEARCH_PAGES": "4",
            "GOOGLE_CUSTOM_SEARCH_API_KEY": "google-search-key",
            "GOOGLE_CUSTOM_SEARCH_CX": "search-engine-id",
            "GOOGLE_CUSTOM_SEARCH_IMAGE_PAGES": "2",
            "GOOGLE_CUSTOM_SEARCH_WEB_PAGES": "3",
        },
        transport=FakeJsonTransport({"items": []}),
    )

    naver_client = runtime.naver_adapter.client
    google_search_client = runtime.google_custom_search_adapter.client

    assert naver_client.image_pages == 2
    assert naver_client.blog_pages == 3
    assert naver_client.web_pages == 4
    assert google_search_client.image_pages == 2
    assert google_search_client.web_pages == 3


def test_provider_runtime_reads_bounded_auto_naver_query_limit():
    runtime = build_provider_runtime(
        env={
            "COPYRIGHTER_AUTO_NAVER_QUERY_LIMIT": "25",
            "COPYRIGHTER_AUTO_NAVER_BLOG_QUERY_LIMIT": "25",
        "COPYRIGHTER_AUTO_NAVER_WEB_QUERY_LIMIT": "25",
        "COPYRIGHTER_AUTO_GOOGLE_CUSTOM_QUERY_LIMIT": "25",
        "COPYRIGHTER_SEARCH_RESULT_COMPARE_LIMIT": "50",
        "COPYRIGHTER_SEARCH_RESULT_PAGE_IMAGE_LIMIT": "25",
        "COPYRIGHTER_SEARCH_RESULT_SIMILARITY_THRESHOLD": "10",
    },
    transport=FakeJsonTransport({}),
)

    assert runtime.auto_naver_query_limit == 10
    assert runtime.auto_naver_blog_query_limit == 10
    assert runtime.auto_naver_web_query_limit == 10
    assert runtime.auto_google_custom_query_limit == 10
    assert runtime.search_result_compare_limit == 20
    assert runtime.search_result_page_image_limit == 10
    assert runtime.search_result_similarity_threshold == 1.0


def test_provider_runtime_clamps_search_result_similarity_threshold():
    runtime = build_provider_runtime(
        env={"COPYRIGHTER_SEARCH_RESULT_SIMILARITY_THRESHOLD": "-0.2"},
        transport=FakeJsonTransport({}),
    )

    assert runtime.search_result_similarity_threshold == 0.0


def test_provider_runtime_leaves_missing_env_providers_disabled():
    runtime = build_provider_runtime(env={}, transport=FakeJsonTransport({}))

    assert runtime.naver_adapter is None
    assert runtime.google_adapter is None
    assert runtime.google_custom_search_adapter is None
    assert runtime.llm_assistant is not None
    assert runtime.provider_payloads["naver"]["enabled"] is False
    assert runtime.provider_payloads["google"]["lastFailure"] == "missing GOOGLE_CLOUD_VISION_API_KEY"
    assert runtime.provider_payloads["google_search"]["lastFailure"] == "missing GOOGLE_CUSTOM_SEARCH_API_KEY or GOOGLE_CUSTOM_SEARCH_CX"
    assert runtime.provider_payloads["google_search"]["requiredEnv"] == [
        "GOOGLE_CUSTOM_SEARCH_API_KEY",
        "GOOGLE_CUSTOM_SEARCH_CX",
    ]
    assert runtime.provider_payloads["google_search"]["configuredEnv"] == {
        "GOOGLE_CUSTOM_SEARCH_API_KEY": False,
        "GOOGLE_CUSTOM_SEARCH_CX": False,
    }
    assert runtime.provider_payloads["llm"]["enabled"] is True
    assert runtime.provider_payloads["llm"]["compliance"] == "Ollama local API configured (qwen2.5:0.5b-instruct)"
