"""
Tests for Phase 27: Agent Marketplace Payments.
"""

import json
import pytest


@pytest.fixture(autouse=True)
def _isolate(tmp_path, monkeypatch):
    payments = tmp_path / "payments"
    ledgers = payments / "ledgers"
    escrow = payments / "escrow"
    for d in (payments, ledgers, escrow):
        d.mkdir(parents=True, exist_ok=True)

    import brynq.server as srv
    monkeypatch.setattr(srv, "BROKER_DIR", tmp_path)

    import brynq.marketplace_payments as mp
    monkeypatch.setattr(mp, "PAYMENTS_DIR", payments)
    monkeypatch.setattr(mp, "LEDGERS_DIR", ledgers)
    monkeypatch.setattr(mp, "ESCROW_DIR", escrow)
    monkeypatch.setattr(mp, "BALANCES_FILE", payments / "balances.json")


class TestSignupBonus:
    def test_grant_bonus(self):
        from brynq.marketplace_payments import grant_signup_bonus, get_balance
        result = grant_signup_bonus("new-agent")
        assert result["bonus"] == 100
        assert get_balance("new-agent") == 100

    def test_no_double_bonus(self):
        from brynq.marketplace_payments import grant_signup_bonus
        grant_signup_bonus("agent-x")
        result = grant_signup_bonus("agent-x")
        assert "error" in result


class TestBalances:
    def test_initial_balance(self):
        from brynq.marketplace_payments import get_balance
        assert get_balance("nobody") == 0.0

    def test_balance_after_bonus(self):
        from brynq.marketplace_payments import grant_signup_bonus, get_balance
        grant_signup_bonus("b1")
        assert get_balance("b1") == 100.0


class TestEscrow:
    def _fund(self, agent_id, amount=500):
        from brynq.marketplace_payments import _record_tx
        _record_tx(agent_id, "deposit", amount, "Test funding")

    def test_create_escrow(self):
        self._fund("payer")
        from brynq.marketplace_payments import create_escrow, get_balance
        result = create_escrow("task-1", "payer", 100, "Test task")
        assert result["status"] == "held"
        assert get_balance("payer") == 400.0

    def test_create_escrow_insufficient(self):
        from brynq.marketplace_payments import create_escrow
        result = create_escrow("task-2", "broke", 100)
        assert "error" in result

    def test_create_escrow_negative(self):
        from brynq.marketplace_payments import create_escrow
        result = create_escrow("task-3", "x", -50)
        assert "error" in result

    def test_release_escrow(self):
        self._fund("payer2")
        from brynq.marketplace_payments import create_escrow, release_escrow, get_balance
        create_escrow("task-4", "payer2", 100)
        result = release_escrow("task-4", "worker1", rating=5.0)
        assert result["worker_payout"] > 0
        assert result["platform_fee"] > 0
        assert get_balance("worker1") > 0

    def test_release_with_rating_bonus(self):
        self._fund("payer3")
        from brynq.marketplace_payments import create_escrow, release_escrow
        create_escrow("task-5", "payer3", 100)
        result = release_escrow("task-5", "worker2", rating=5.0)
        assert result["rating_bonus"] > 0

    def test_release_low_rating_no_bonus(self):
        self._fund("payer4")
        from brynq.marketplace_payments import create_escrow, release_escrow
        create_escrow("task-6", "payer4", 100)
        result = release_escrow("task-6", "worker3", rating=3.0)
        assert result["rating_bonus"] == 0

    def test_release_nonexistent(self):
        from brynq.marketplace_payments import release_escrow
        result = release_escrow("nope", "worker")
        assert "error" in result

    def test_double_release(self):
        self._fund("payer5")
        from brynq.marketplace_payments import create_escrow, release_escrow
        create_escrow("task-7", "payer5", 100)
        release_escrow("task-7", "w1")
        result = release_escrow("task-7", "w2")
        assert "error" in result

    def test_refund_escrow(self):
        self._fund("payer6")
        from brynq.marketplace_payments import create_escrow, refund_escrow, get_balance
        create_escrow("task-8", "payer6", 200)
        assert get_balance("payer6") == 300.0
        refund_escrow("task-8")
        assert get_balance("payer6") == 500.0

    def test_refund_nonexistent(self):
        from brynq.marketplace_payments import refund_escrow
        result = refund_escrow("nope")
        assert "error" in result


class TestTransfers:
    def _fund(self, agent_id, amount=500):
        from brynq.marketplace_payments import _record_tx
        _record_tx(agent_id, "deposit", amount, "Funding")

    def test_transfer(self):
        self._fund("sender")
        from brynq.marketplace_payments import transfer_credits, get_balance
        result = transfer_credits("sender", "receiver", 50, "Thanks!")
        assert result["from_balance"] == 450.0
        assert result["to_balance"] == 50.0

    def test_transfer_insufficient(self):
        from brynq.marketplace_payments import transfer_credits
        result = transfer_credits("empty", "someone", 100)
        assert "error" in result

    def test_transfer_negative(self):
        from brynq.marketplace_payments import transfer_credits
        result = transfer_credits("a", "b", -10)
        assert "error" in result

    def test_transfer_self(self):
        from brynq.marketplace_payments import transfer_credits
        result = transfer_credits("me", "me", 10)
        assert "error" in result


class TestBounties:
    def _fund(self, agent_id, amount=500):
        from brynq.marketplace_payments import _record_tx
        _record_tx(agent_id, "deposit", amount, "Funding")

    def test_post_and_claim_bounty(self):
        self._fund("poster")
        from brynq.marketplace_payments import post_bounty, claim_bounty, get_balance
        post_bounty("bounty-1", "poster", 200, "Fix critical bug")
        assert get_balance("poster") == 300.0
        result = claim_bounty("bounty-1", "hunter", rating=5.0)
        assert result["worker_payout"] > 0
        assert get_balance("hunter") > 0


class TestLedger:
    def test_get_ledger(self):
        from brynq.marketplace_payments import grant_signup_bonus, get_ledger
        grant_signup_bonus("ledger-agent")
        ledger = get_ledger("ledger-agent")
        assert len(ledger) == 1
        assert ledger[0]["tx_type"] == "signup_bonus"

    def test_empty_ledger(self):
        from brynq.marketplace_payments import get_ledger
        assert get_ledger("ghost") == []


class TestPlatformRevenue:
    def _fund(self, agent_id, amount=500):
        from brynq.marketplace_payments import _record_tx
        _record_tx(agent_id, "deposit", amount, "Funding")

    def test_platform_revenue(self):
        self._fund("rev-payer")
        from brynq.marketplace_payments import create_escrow, release_escrow, get_platform_revenue
        create_escrow("rev-task", "rev-payer", 100)
        release_escrow("rev-task", "rev-worker")
        revenue = get_platform_revenue()
        assert revenue["total_revenue"] > 0
        assert revenue["total_transactions"] >= 1


class TestEconomyStats:
    def test_economy_stats(self):
        from brynq.marketplace_payments import grant_signup_bonus, get_economy_stats
        grant_signup_bonus("econ-1")
        grant_signup_bonus("econ-2")
        stats = get_economy_stats()
        assert stats["total_credits_in_circulation"] == 200.0
        assert stats["active_agents"] == 2
