"""Unit tests for SDK types."""

import pytest
from synor_compute.types import (
    ProcessorType,
    Precision,
    BalancingStrategy,
    TaskPriority,
    JobStatus,
    SynorConfig,
    JobResult,
    JobMetrics,
    PricingInfo,
)


class TestProcessorType:
    """Tests for ProcessorType enum."""

    def test_all_processor_types(self):
        """Should have all expected processor types."""
        expected = ["cpu", "gpu", "tpu", "npu", "lpu", "fpga", "dsp", "webgpu", "wasm", "auto"]
        actual = [p.value for p in ProcessorType]

        for e in expected:
            assert e in actual

    def test_processor_value(self):
        """Should have correct values."""
        assert ProcessorType.GPU.value == "gpu"
        assert ProcessorType.TPU.value == "tpu"
        assert ProcessorType.AUTO.value == "auto"


class TestPrecision:
    """Tests for Precision enum."""

    def test_all_precision_types(self):
        """Should have all expected precision types."""
        expected = ["fp64", "fp32", "fp16", "bf16", "int8", "int4"]
        actual = [p.value for p in Precision]

        for e in expected:
            assert e in actual

    def test_precision_value(self):
        """Should have correct values."""
        assert Precision.FP64.value == "fp64"
        assert Precision.FP32.value == "fp32"
        assert Precision.FP16.value == "fp16"


class TestBalancingStrategy:
    """Tests for BalancingStrategy enum."""

    def test_all_strategies(self):
        """Should have all expected strategies."""
        expected = ["cost", "latency", "energy", "throughput", "auto"]
        actual = [s.value for s in BalancingStrategy]

        for e in expected:
            assert e in actual


class TestTaskPriority:
    """Tests for TaskPriority enum."""

    def test_all_priorities(self):
        """Should have all expected priorities."""
        expected = ["critical", "high", "normal", "low", "background"]
        actual = [p.value for p in TaskPriority]

        for e in expected:
            assert e in actual


class TestJobStatus:
    """Tests for JobStatus enum."""

    def test_all_statuses(self):
        """Should have all expected statuses."""
        expected = ["pending", "queued", "running", "completed", "failed", "cancelled"]
        actual = [s.value for s in JobStatus]

        for e in expected:
            assert e in actual


class TestSynorConfig:
    """Tests for SynorConfig dataclass."""

    def test_create_with_defaults(self):
        """Should create config with defaults."""
        config = SynorConfig(api_key="test-key")

        assert config.api_key == "test-key"
        assert config.base_url == "https://api.synor.io/compute/v1"
        assert config.timeout == 30

    def test_create_with_custom_values(self):
        """Should create config with custom values."""
        config = SynorConfig(
            api_key="test-key",
            base_url="https://custom.api.com",
            timeout=60,
            default_processor=ProcessorType.GPU,
            default_precision=Precision.FP16,
        )

        assert config.base_url == "https://custom.api.com"
        assert config.timeout == 60
        assert config.default_processor == ProcessorType.GPU
        assert config.default_precision == Precision.FP16


class TestJobResult:
    """Tests for JobResult dataclass."""

    def test_create_job_result(self):
        """Should create job result."""
        result = JobResult(
            job_id="job-123",
            status=JobStatus.COMPLETED,
            result={"data": "value"},
            execution_time_ms=150,
            processor=ProcessorType.GPU,
        )

        assert result.job_id == "job-123"
        assert result.status == JobStatus.COMPLETED
        assert result.execution_time_ms == 150

    def test_is_success(self):
        """Should identify successful job."""
        success = JobResult(
            job_id="job-1",
            status=JobStatus.COMPLETED,
            result="data",
        )
        failure = JobResult(
            job_id="job-2",
            status=JobStatus.FAILED,
            error="Error message",
        )

        assert success.is_success()
        assert not failure.is_success()

    def test_is_failed(self):
        """Should identify failed job."""
        success = JobResult(
            job_id="job-1",
            status=JobStatus.COMPLETED,
            result="data",
        )
        failure = JobResult(
            job_id="job-2",
            status=JobStatus.FAILED,
            error="Error message",
        )

        assert not success.is_failed()
        assert failure.is_failed()


class TestJobMetrics:
    """Tests for JobMetrics dataclass."""

    def test_create_metrics(self):
        """Should create job metrics."""
        metrics = JobMetrics(
            queue_time_ms=10,
            compute_time_ms=100,
            transfer_time_ms=5,
            total_time_ms=115,
            flops=1e12,
            memory_used_mb=1024,
        )

        assert metrics.compute_time_ms == 100
        assert metrics.flops == 1e12


class TestPricingInfo:
    """Tests for PricingInfo dataclass."""

    def test_create_pricing_info(self):
        """Should create pricing info."""
        pricing = PricingInfo(
            processor=ProcessorType.GPU,
            price_per_second=0.0001,
            available_units=100,
            utilization_percent=75.5,
        )

        assert pricing.processor == ProcessorType.GPU
        assert pricing.price_per_second == 0.0001
        assert pricing.available_units == 100

    def test_optional_fields(self):
        """Should handle optional fields."""
        pricing = PricingInfo(
            processor=ProcessorType.TPU,
            price_per_second=0.0002,
            available_units=50,
            utilization_percent=60.0,
            aws_equivalent_price=0.0010,
            savings_percent=80.0,
        )

        assert pricing.aws_equivalent_price == 0.0010
        assert pricing.savings_percent == 80.0
