from __future__ import annotations

import json
import os
from typing import Any, Dict

import pytest

from its_ai import (
    ItsAIClient,
    ItsAIAsyncClient,
    AnalyzeTextResult,
    AnalyzeBatchItemResult,
    ValidationError,
    AuthenticationFailed,
    LowWords,
    ManyWords,
    OnlyEnglish,
    RateLimitExceeded,
)


class DummyResponse:
    def __init__(self, status_code: int, json_data: Any = None, text: str = "") -> None:
        self.status_code = status_code
        self._json = json_data
        self.text = text
        self.headers: Dict[str, str] = {}

    def json(self) -> Any:
        if self._json is None:
            raise ValueError("no json")
        return self._json


class DummySession:
    def __init__(self) -> None:
        self.calls = []

    def post(self, url, headers=None, json=None, timeout=None):  # type: ignore[override]
        self.calls.append((url, json))
        # emulate success for /api/text
        if url.endswith("/api/text"):
            return DummyResponse(200, {"answer": 0.5})
        if url.endswith("/api/batch/"):
            answer = [
                {"text": t, "answer": 0.7, "segmentation_tokens": None, "deep_scan": False, "error": None}
                for t in json["texts"]
            ]
            return DummyResponse(200, {"answer": answer})
        return DummyResponse(404, {"type": "not_found", "error": "not found"})

    def close(self) -> None:
        pass


def test_sync_success_single(monkeypatch):
    client = ItsAIClient(api_key="sk_test", session=DummySession())
    res = client.analyze_text("hello")
    assert isinstance(res, AnalyzeTextResult)
    assert 0.0 <= res.answer <= 1.0


def test_sync_success_batch(monkeypatch):
    client = ItsAIClient(api_key="sk_test", session=DummySession())
    res = client.analyze_batch(["hello", "world"])  # type: ignore[list-item]
    assert len(res) == 2
    assert all(isinstance(x, AnalyzeBatchItemResult) for x in res)


def test_validation_errors():
    with pytest.raises(ValidationError):
        ItsAIClient(api_key="")
    client = ItsAIClient(api_key="sk_test", session=DummySession())
    with pytest.raises(ValidationError):
        client.analyze_text("")
    with pytest.raises(ValidationError):
        client.analyze_batch([])


def test_error_mapping_http():
    class ErrSession(DummySession):
        def post(self, url, headers=None, json=None, timeout=None):  # type: ignore[override]
            return DummyResponse(401, {"type": "authentication_failed", "error": "bad key"})

    client = ItsAIClient(api_key="sk_test", session=ErrSession())
    with pytest.raises(AuthenticationFailed):
        client.analyze_text("hello")


@pytest.mark.skipif(os.getenv("ITS_AI_E2E") != "1", reason="e2e disabled")
def test_e2e_single():
    key = os.getenv("ITS_AI_API_KEY")
    if not key:
        pytest.skip("no key")
    with ItsAIClient(api_key=key) as client:
        long_text = (
            "This is a sufficiently long English text for testing the ITS-AI API. "
            "We want to ensure the input meets the minimum length requirement of two hundred characters. "
            "Therefore, we will continue adding more sentences to reach the threshold and avoid low_words errors. "
            "This text should be more than enough to pass validation."
        )
        res = client.analyze_text(long_text)
        assert 0.0 <= res.answer <= 1.0


