"""Tests for type classes, enums, and data structures."""

import pytest

from skytells.types.predict import (
    PredictionRequest,
    PredictionSource,
    PredictionStatus,
    PredictionType,
    PredictionsListOptions,
    RunOptions,
    WaitOptions,
)
from skytells.types.models import (
    ModelFieldsOptions,
    ModelPrivacy,
    ModelType,
    PricingOperator,
    PricingUnit,
)
from skytells.types.shared import (
    ClientOptions,
    PaginatedResponse,
    Pagination,
    RetryOptions,
)


class TestPredictionStatus:
    def test_values(self):
        assert PredictionStatus.PENDING == "pending"
        assert PredictionStatus.STARTING == "starting"
        assert PredictionStatus.STARTED == "started"
        assert PredictionStatus.PROCESSING == "processing"
        assert PredictionStatus.SUCCEEDED == "succeeded"
        assert PredictionStatus.FAILED == "failed"
        assert PredictionStatus.CANCELLED == "cancelled"

    def test_is_string(self):
        assert isinstance(PredictionStatus.SUCCEEDED, str)

    def test_equality_with_string(self):
        assert PredictionStatus.SUCCEEDED == "succeeded"


class TestPredictionType:
    def test_values(self):
        assert PredictionType.INFERENCE == "inference"
        assert PredictionType.TRAINING == "training"


class TestPredictionSource:
    def test_values(self):
        assert PredictionSource.API == "api"
        assert PredictionSource.CLI == "cli"
        assert PredictionSource.WEB == "web"


class TestModelType:
    def test_values(self):
        assert ModelType.IMAGE == "image"
        assert ModelType.VIDEO == "video"
        assert ModelType.AUDIO == "audio"
        assert ModelType.MUSIC == "music"
        assert ModelType.TEXT == "text"
        assert ModelType.CODE == "code"
        assert ModelType.MULTIMODAL == "multimodal"


class TestModelPrivacy:
    def test_values(self):
        assert ModelPrivacy.PUBLIC == "public"
        assert ModelPrivacy.PRIVATE == "private"


class TestPricingUnit:
    def test_values(self):
        assert PricingUnit.IMAGE == "image"
        assert PricingUnit.VIDEO == "video"
        assert PricingUnit.TOKEN == "token"
        assert PricingUnit.MINUTE == "minute"
        assert PricingUnit.FIVE_SECONDS == "5 seconds"


class TestPricingOperator:
    def test_values(self):
        assert PricingOperator.EQUALS == "equals"
        assert PricingOperator.DOUBLE_EQUALS == "=="


class TestPredictionRequest:
    def test_basic_to_dict(self):
        req = PredictionRequest(model="flux-pro", input={"prompt": "test"})
        d = req.to_dict()
        assert d["model"] == "flux-pro"
        assert d["input"] == {"prompt": "test"}
        assert "await" not in d
        assert "stream" not in d
        assert "webhook" not in d

    def test_await_true_included(self):
        req = PredictionRequest(model="flux-pro", input={}, await_=True)
        d = req.to_dict()
        assert d["await"] is True

    def test_stream_true_included(self):
        req = PredictionRequest(model="flux-pro", input={}, stream=True)
        d = req.to_dict()
        assert d["stream"] is True

    def test_webhook_included(self):
        wh = {"url": "https://example.com", "events": ["completed"]}
        req = PredictionRequest(model="flux-pro", input={}, webhook=wh)
        d = req.to_dict()
        assert d["webhook"] == wh

    def test_from_dict(self):
        req = PredictionRequest.from_dict({
            "model": "flux-pro",
            "input": {"prompt": "cat"},
            "await": True,
            "stream": False,
        })
        assert req.model == "flux-pro"
        assert req.input == {"prompt": "cat"}
        assert req.await_ is True
        assert req.stream is False


class TestRunOptions:
    def test_basic(self):
        opts = RunOptions(input={"prompt": "dog"})
        d = opts.to_dict()
        assert d["input"] == {"prompt": "dog"}
        assert "webhook" not in d
        assert "stream" not in d

    def test_stream(self):
        opts = RunOptions(input={}, stream=True)
        assert opts.to_dict()["stream"] is True

    def test_from_dict(self):
        opts = RunOptions.from_dict({"input": {"prompt": "bird"}, "stream": True})
        assert opts.input == {"prompt": "bird"}
        assert opts.stream is True


class TestWaitOptions:
    def test_defaults(self):
        opts = WaitOptions()
        assert opts.interval == 5000
        assert opts.max_wait is None

    def test_custom(self):
        opts = WaitOptions(interval=2000, max_wait=60000)
        assert opts.interval == 2000
        assert opts.max_wait == 60000

    def test_from_dict(self):
        opts = WaitOptions.from_dict({"interval": 3000, "max_wait": 90000})
        assert opts.interval == 3000
        assert opts.max_wait == 90000


class TestPredictionsListOptions:
    def test_defaults(self):
        opts = PredictionsListOptions()
        assert opts.page is None
        assert opts.since is None
        assert opts.until is None
        assert opts.model is None

    def test_from_dict(self):
        opts = PredictionsListOptions.from_dict({
            "page": 2,
            "since": "2026-01-01",
            "until": "2026-03-16",
            "model": "flux-pro",
        })
        assert opts.page == 2
        assert opts.since == "2026-01-01"
        assert opts.until == "2026-03-16"
        assert opts.model == "flux-pro"


class TestRetryOptions:
    def test_defaults(self):
        retry = RetryOptions()
        assert retry.retries == 0
        assert retry.retry_delay == 1000
        assert retry.retry_on == [429, 500, 502, 503, 504]

    def test_custom(self):
        retry = RetryOptions(retries=3, retry_delay=500, retry_on=[503])
        assert retry.retries == 3
        assert retry.retry_delay == 500
        assert retry.retry_on == [503]

    def test_from_dict(self):
        retry = RetryOptions.from_dict({"retries": 2, "retry_delay": 2000})
        assert retry.retries == 2
        assert retry.retry_delay == 2000
        assert retry.retry_on == [429, 500, 502, 503, 504]


class TestClientOptions:
    def test_defaults(self):
        opts = ClientOptions()
        assert opts.base_url is None
        assert opts.timeout == 60000
        assert opts.headers == {}
        assert opts.retry.retries == 0

    def test_retry_from_dict(self):
        opts = ClientOptions(retry={"retries": 3})
        assert opts.retry.retries == 3

    def test_retry_from_object(self):
        r = RetryOptions(retries=5)
        opts = ClientOptions(retry=r)
        assert opts.retry.retries == 5


class TestPagination:
    def test_from_dict(self):
        p = Pagination({"current_page": 2, "per_page": 20, "total": 100, "last_page": 5})
        assert p.current_page == 2
        assert p.per_page == 20
        assert p.total == 100
        assert p.last_page == 5

    def test_to_dict(self):
        p = Pagination({"current_page": 1, "per_page": 10, "total": 50, "last_page": 5})
        d = p.to_dict()
        assert d["current_page"] == 1
        assert d["total"] == 50


class TestPaginatedResponse:
    def test_basic(self):
        raw = {
            "data": [{"id": "pred_1"}, {"id": "pred_2"}],
            "pagination": {"current_page": 1, "per_page": 10, "total": 2, "last_page": 1},
        }
        pr = PaginatedResponse(raw)
        assert len(pr.data) == 2
        assert pr.pagination.total == 2
        assert pr.pagination.current_page == 1

    def test_to_dict(self):
        raw = {
            "data": [{"id": "pred_1"}],
            "pagination": {"current_page": 1, "per_page": 10, "total": 1, "last_page": 1},
        }
        pr = PaginatedResponse(raw)
        d = pr.to_dict()
        assert "data" in d
        assert "pagination" in d


class TestModelFieldsOptions:
    def test_empty(self):
        opts = ModelFieldsOptions()
        assert opts.fields == []

    def test_with_fields(self):
        opts = ModelFieldsOptions(fields=["input_schema", "output_schema"])
        assert "input_schema" in opts.fields

    def test_from_dict(self):
        opts = ModelFieldsOptions.from_dict({"fields": ["input_schema"]})
        assert opts.fields == ["input_schema"]
