"""Tests for MeshLedger Pydantic type models."""

import pytest
from pydantic import ValidationError as PydanticValidationError

from meshledger.types import (
    Agent,
    AgentDashboard,
    AgentMatch,
    CancelJobResponse,
    Chain,
    CreateJobResponse,
    DeliverJobResponse,
    Dispute,
    DisputeJobResponse,
    DisputeStatus,
    Job,
    JobStatus,
    MarketplaceStats,
    PaginatedList,
    RateJobResponse,
    Rating,
    RefundApproveResponse,
    RegisterAgentResponse,
    ReleaseJobResponse,
    Reputation,
    Skill,
    Token,
)


class TestEnums:
    def test_job_status_values(self):
        assert JobStatus.FUNDED == "funded"
        assert JobStatus.DELIVERED == "delivered"
        assert JobStatus.RELEASED == "released"
        assert JobStatus.AUTO_RELEASED == "auto_released"
        assert JobStatus.DISPUTED == "disputed"
        assert JobStatus.CANCELLED == "cancelled"

    def test_chain_values(self):
        assert Chain.BASE == "base"
        assert Chain.SOLANA == "solana"

    def test_token_values(self):
        assert Token.USDC == "USDC"
        assert Token.SOL == "SOL"
        assert Token.ETH == "ETH"

    def test_dispute_status(self):
        assert DisputeStatus.DISPUTED == "disputed"
        assert DisputeStatus.RESOLVED == "resolved"


class TestReputation:
    def test_valid(self):
        r = Reputation(
            score=85.5,
            completion_rate=0.95,
            quality_score=4.2,
            dispute_rate=0.02,
            response_time_percentile=0.9,
            diversity_score=0.7,
            total_transactions=42,
            is_new=False,
        )
        assert r.score == 85.5
        assert r.total_transactions == 42
        assert r.is_new is False


class TestAgent:
    def test_minimal(self):
        a = Agent(
            agent_id="abc-123",
            name="test-agent",
            description="A test agent",
            chains=[Chain.BASE],
            capabilities=["testing"],
        )
        assert a.agent_id == "abc-123"
        assert a.chains == [Chain.BASE]
        assert a.reputation is None

    def test_full(self):
        a = Agent(
            agent_id="abc-123",
            name="test-agent",
            description="desc",
            wallet_address_base="0xabc",
            chains=[Chain.BASE, Chain.SOLANA],
            capabilities=["a", "b"],
            reputation=Reputation(
                score=50,
                completion_rate=0.8,
                quality_score=3.5,
                dispute_rate=0.1,
                response_time_percentile=0.5,
                diversity_score=0.3,
                total_transactions=10,
                is_new=True,
            ),
            website="https://example.com",
            created_at="2025-01-01T00:00:00Z",
        )
        assert a.reputation is not None
        assert a.reputation.score == 50

    def test_missing_required_field(self):
        with pytest.raises(PydanticValidationError):
            Agent(agent_id="abc", description="d", chains=[], capabilities=[])  # missing name


class TestSkill:
    def test_valid(self):
        s = Skill(
            skill_id="s1",
            agent_id="a1",
            name="Code Review",
            description="Reviews code",
            capabilities=["code-review"],
            price=5.0,
            price_token=Token.USDC,
            price_chain=Chain.BASE,
        )
        assert s.price == 5.0
        assert s.price_token == Token.USDC


class TestJob:
    def test_minimal(self):
        j = Job(job_id="j1", title="Test Job", status=JobStatus.FUNDED)
        assert j.status == JobStatus.FUNDED
        assert j.deliverer_id is None

    def test_full(self):
        j = Job(
            job_id="j1",
            title="Test Job",
            description="Full job",
            required_capabilities=["testing"],
            chain=Chain.BASE,
            token=Token.USDC,
            listed_price=10.0,
            service_fee=0.5,
            total_charged=10.5,
            status=JobStatus.DELIVERED,
            customer_id="c1",
            deliverer_id="d1",
            escrow_tx_hash="0xabc",
            auto_release_at="2025-01-02T00:00:00Z",
        )
        assert j.total_charged == 10.5


class TestDispute:
    def test_valid(self):
        d = Dispute(
            dispute_id="d1",
            job_id="j1",
            status=DisputeStatus.DISPUTED,
            reason="Bad work",
        )
        assert d.ruling is None


class TestRating:
    def test_valid(self):
        r = Rating(
            rating_id="r1",
            job_id="j1",
            rater_id="a1",
            rated_id="a2",
            score=5,
        )
        assert r.score == 5


class TestMarketplaceStats:
    def test_valid(self):
        s = MarketplaceStats(
            total_agents=100,
            total_skills=500,
            total_jobs_completed=1000,
            total_volume_usd=50000.0,
            active_escrows=25,
        )
        assert s.total_agents == 100


class TestResponseModels:
    def test_register_response(self):
        r = RegisterAgentResponse(
            agent_id="a1", api_key="ml_sk_test123", name="test"
        )
        assert r.api_key.startswith("ml_sk_")

    def test_create_job_response(self):
        r = CreateJobResponse(
            job_id="j1",
            escrow_tx_hash="0x123",
            total_charged=10.5,
            listed_price=10.0,
            service_fee=0.5,
            status=JobStatus.FUNDED,
        )
        assert r.status == JobStatus.FUNDED

    def test_deliver_response(self):
        r = DeliverJobResponse(
            job_id="j1",
            status="delivered",
            auto_release_at="2025-01-02T00:00:00Z",
            message="Customer has 24 hours.",
        )
        assert r.status == "delivered"

    def test_release_response(self):
        r = ReleaseJobResponse(
            job_id="j1",
            status="released",
            release_tx_hash="0xabc",
            amount_to_deliverer=9.5,
            fee_to_treasury=0.5,
        )
        assert r.amount_to_deliverer == 9.5

    def test_cancel_response(self):
        r = CancelJobResponse(
            job_id="j1",
            status="cancelled",
            amount_refunded=10.0,
            refund_tx_hash="0xdef",
        )
        assert r.status == "cancelled"

    def test_dispute_response(self):
        r = DisputeJobResponse(
            dispute_id="d1",
            job_id="j1",
            status="disputed",
            message="AI Judge will evaluate.",
        )
        assert r.dispute_id == "d1"

    def test_rate_response(self):
        r = RateJobResponse(
            rating_id="r1", job_id="j1", rated_id="a2", score=4
        )
        assert r.score == 4

    def test_refund_approve_response(self):
        r = RefundApproveResponse(
            job_id="j1",
            status="refunded",
            refund_tx_hash="0x999",
            amount_refunded=10.0,
        )
        assert r.amount_refunded == 10.0


class TestPaginatedList:
    def test_with_cursor(self):
        p = PaginatedList(items=[{"id": 1}], cursor="abc", has_more=True)
        assert p.has_more is True
        assert p.cursor == "abc"

    def test_without_cursor(self):
        p = PaginatedList(items=[], has_more=False)
        assert p.cursor is None


class TestAgentMatch:
    def test_valid(self):
        m = AgentMatch(
            agent_id="a1",
            name="test",
            matching_capabilities=["code-review"],
            price_range={"min": 1.0, "max": 10.0},
        )
        assert m.price_range["min"] == 1.0
