"""
Phase 27: Agent Marketplace Payments.

Credit-based economy for the AI agent marketplace. Agents earn credits
for completing tasks, spend credits to hire other agents, and can
withdraw to real currency via the billing system.

Features:
  - CREDIT LEDGER: Append-only transaction log per agent
  - ESCROW: Credits locked when a task is posted, released on completion
  - EARNINGS: Agents earn credits based on task priority and rating
  - BOUNTIES: Premium credit rewards for urgent/difficult tasks
  - WITHDRAWALS: Convert credits to real currency (via Square/Bitcoin)
  - PLATFORM FEE: Brynq takes a configurable cut of each transaction

Storage:
  state/broker/payments/
    ledgers/{agent_id}.jsonl   — transaction history
    escrow/{task_id}.json      — active escrow holds
    balances.json              — cached balance snapshot
"""

import json
import uuid
from datetime import datetime, timezone
from pathlib import Path
from typing import Optional

from brynq.server import (
    BROKER_DIR,
    SESSION_ID,
    SESSION_NAME,
    PLATFORM,
    _write_json_sync,
    _append_jsonl_sync,
)

# ── Paths ──────────────────────────────────────────────────────────────────

PAYMENTS_DIR = BROKER_DIR / "payments"
LEDGERS_DIR = PAYMENTS_DIR / "ledgers"
ESCROW_DIR = PAYMENTS_DIR / "escrow"
BALANCES_FILE = PAYMENTS_DIR / "balances.json"

for _d in (PAYMENTS_DIR, LEDGERS_DIR, ESCROW_DIR):
    _d.mkdir(parents=True, exist_ok=True)

# ── Config ─────────────────────────────────────────────────────────────────

PLATFORM_FEE_RATE = 0.10  # 10% platform fee
SIGNUP_BONUS = 100        # New agents get 100 credits
PRIORITY_MULTIPLIERS = {
    "low": 0.5,
    "normal": 1.0,
    "high": 2.0,
    "urgent": 5.0,
}

VALID_TX_TYPES = (
    "signup_bonus", "task_earned", "task_paid", "escrow_hold",
    "escrow_release", "escrow_refund", "platform_fee", "bounty_earned",
    "transfer", "withdrawal", "deposit", "adjustment",
)


# ── Ledger (Append-Only Transactions) ──────────────────────────────────────


def _record_tx(
    agent_id: str,
    tx_type: str,
    amount: float,
    description: str,
    reference_id: str = "",
) -> dict:
    """Record a transaction to an agent's ledger."""
    tx = {
        "tx_id": uuid.uuid4().hex[:12],
        "agent_id": agent_id,
        "tx_type": tx_type,
        "amount": round(amount, 2),
        "description": description,
        "reference_id": reference_id,
        "timestamp": datetime.now(timezone.utc).isoformat(),
    }
    _append_jsonl_sync(LEDGERS_DIR / f"{agent_id}.jsonl", tx)
    _update_balance_cache(agent_id)
    return tx


def get_ledger(agent_id: str, limit: int = 50) -> list[dict]:
    """Get an agent's transaction history."""
    path = LEDGERS_DIR / f"{agent_id}.jsonl"
    try:
        entries = []
        with open(path, "r", encoding="utf-8") as f:
            for line in f:
                line = line.strip()
                if line:
                    try:
                        entries.append(json.loads(line))
                    except json.JSONDecodeError:
                        continue
        return entries[-limit:]
    except (FileNotFoundError, OSError):
        return []


# ── Balance Management ─────────────────────────────────────────────────────


def get_balance(agent_id: str) -> float:
    """Get an agent's current credit balance."""
    balances = _load_balances()
    return balances.get(agent_id, 0.0)


def _update_balance_cache(agent_id: str) -> float:
    """Recompute an agent's balance from their full ledger."""
    ledger = get_ledger(agent_id, limit=10000)
    balance = sum(tx.get("amount", 0) for tx in ledger)
    balance = round(balance, 2)

    balances = _load_balances()
    balances[agent_id] = balance
    _write_json_sync(BALANCES_FILE, balances)
    return balance


def _load_balances() -> dict:
    try:
        return json.loads(BALANCES_FILE.read_text("utf-8"))
    except (FileNotFoundError, json.JSONDecodeError, OSError):
        return {}


# ── Agent Onboarding ───────────────────────────────────────────────────────


def grant_signup_bonus(agent_id: str) -> dict:
    """Grant the signup bonus to a new agent."""
    existing = get_ledger(agent_id, limit=1)
    if existing and any(tx.get("tx_type") == "signup_bonus" for tx in get_ledger(agent_id, limit=100)):
        return {"error": "Signup bonus already claimed"}

    tx = _record_tx(
        agent_id, "signup_bonus", SIGNUP_BONUS,
        f"Welcome to Brynq! Here's {SIGNUP_BONUS} credits to get started.",
    )
    return {"balance": get_balance(agent_id), "bonus": SIGNUP_BONUS, "tx": tx}


# ── Escrow System ─────────────────────────────────────────────────────────


def create_escrow(
    task_id: str,
    payer_id: str,
    amount: float,
    description: str = "",
) -> dict:
    """Lock credits in escrow for a task.

    The payer's balance is debited. Credits are held until the task
    completes (released to worker) or is cancelled (refunded to payer).
    """
    if amount <= 0:
        return {"error": "Escrow amount must be positive"}

    balance = get_balance(payer_id)
    if balance < amount:
        return {"error": f"Insufficient balance. Have {balance}, need {amount}"}

    escrow = {
        "escrow_id": uuid.uuid4().hex[:12],
        "task_id": task_id,
        "payer_id": payer_id,
        "amount": round(amount, 2),
        "status": "held",
        "description": description,
        "created_at": datetime.now(timezone.utc).isoformat(),
        "released_at": None,
        "released_to": None,
    }

    # Debit the payer
    _record_tx(payer_id, "escrow_hold", -amount,
               f"Escrow hold for task {task_id}", reference_id=task_id)

    _write_json_sync(ESCROW_DIR / f"{task_id}.json", escrow)
    return escrow


def release_escrow(task_id: str, worker_id: str, rating: float = 5.0) -> dict:
    """Release escrow to the worker on task completion.

    Platform fee is deducted. Bonus applied based on rating.
    """
    escrow = _load_escrow(task_id)
    if not escrow:
        return {"error": f"No escrow found for task {task_id}"}
    if escrow["status"] != "held":
        return {"error": f"Escrow is '{escrow['status']}', must be 'held'"}

    amount = escrow["amount"]
    platform_fee = round(amount * PLATFORM_FEE_RATE, 2)
    worker_payout = round(amount - platform_fee, 2)

    # Rating bonus: 5-star = 10% bonus, 4-star = 5%, below = 0
    rating = max(1.0, min(5.0, float(rating)))
    if rating >= 4.5:
        bonus = round(worker_payout * 0.10, 2)
    elif rating >= 4.0:
        bonus = round(worker_payout * 0.05, 2)
    else:
        bonus = 0.0
    worker_payout = round(worker_payout + bonus, 2)

    # Pay the worker
    _record_tx(worker_id, "task_earned", worker_payout,
               f"Payment for task {task_id} (rating: {rating})", reference_id=task_id)

    # Record platform fee
    _record_tx("brynq_platform", "platform_fee", platform_fee,
               f"Fee from task {task_id}", reference_id=task_id)

    escrow["status"] = "released"
    escrow["released_at"] = datetime.now(timezone.utc).isoformat()
    escrow["released_to"] = worker_id
    escrow["platform_fee"] = platform_fee
    escrow["worker_payout"] = worker_payout
    escrow["rating_bonus"] = bonus
    _write_json_sync(ESCROW_DIR / f"{task_id}.json", escrow)

    return {
        "task_id": task_id,
        "worker_id": worker_id,
        "worker_payout": worker_payout,
        "platform_fee": platform_fee,
        "rating_bonus": bonus,
        "worker_balance": get_balance(worker_id),
    }


def refund_escrow(task_id: str) -> dict:
    """Refund escrowed credits back to the payer (task cancelled)."""
    escrow = _load_escrow(task_id)
    if not escrow:
        return {"error": f"No escrow found for task {task_id}"}
    if escrow["status"] != "held":
        return {"error": f"Escrow is '{escrow['status']}', cannot refund"}

    _record_tx(escrow["payer_id"], "escrow_refund", escrow["amount"],
               f"Refund for cancelled task {task_id}", reference_id=task_id)

    escrow["status"] = "refunded"
    escrow["released_at"] = datetime.now(timezone.utc).isoformat()
    _write_json_sync(ESCROW_DIR / f"{task_id}.json", escrow)

    return {"task_id": task_id, "refunded": escrow["amount"],
            "payer_balance": get_balance(escrow["payer_id"])}


def _load_escrow(task_id: str) -> Optional[dict]:
    try:
        return json.loads((ESCROW_DIR / f"{task_id}.json").read_text("utf-8"))
    except (FileNotFoundError, json.JSONDecodeError, OSError):
        return None


# ── Transfers ──────────────────────────────────────────────────────────────


def transfer_credits(
    from_id: str,
    to_id: str,
    amount: float,
    memo: str = "",
) -> dict:
    """Transfer credits between agents."""
    if amount <= 0:
        return {"error": "Transfer amount must be positive"}
    if from_id == to_id:
        return {"error": "Cannot transfer to yourself"}

    balance = get_balance(from_id)
    if balance < amount:
        return {"error": f"Insufficient balance. Have {balance}, need {amount}"}

    _record_tx(from_id, "transfer", -amount,
               f"Transfer to {to_id}: {memo}", reference_id=to_id)
    _record_tx(to_id, "transfer", amount,
               f"Transfer from {from_id}: {memo}", reference_id=from_id)

    return {
        "from": from_id, "to": to_id, "amount": amount,
        "from_balance": get_balance(from_id),
        "to_balance": get_balance(to_id),
    }


# ── Bounties ───────────────────────────────────────────────────────────────


def post_bounty(
    task_id: str,
    poster_id: str,
    amount: float,
    description: str = "",
) -> dict:
    """Post a bounty on a task. Credits are escrowed immediately."""
    return create_escrow(task_id, poster_id, amount, f"Bounty: {description}")


def claim_bounty(task_id: str, claimer_id: str, rating: float = 5.0) -> dict:
    """Claim a bounty reward. Same as releasing escrow to the worker."""
    return release_escrow(task_id, claimer_id, rating=rating)


# ── Platform Revenue ──────────────────────────────────────────────────────


def get_platform_revenue() -> dict:
    """Get Brynq platform's total revenue from fees."""
    ledger = get_ledger("brynq_platform", limit=10000)
    total = sum(tx.get("amount", 0) for tx in ledger)
    return {
        "total_revenue": round(total, 2),
        "total_transactions": len(ledger),
        "fee_rate": PLATFORM_FEE_RATE,
    }


def get_economy_stats() -> dict:
    """Get aggregate marketplace economy statistics."""
    balances = _load_balances()
    total_supply = sum(balances.values())
    active_agents = len([b for b in balances.values() if b > 0])

    escrows = []
    for f in ESCROW_DIR.glob("*.json"):
        try:
            e = json.loads(f.read_text("utf-8"))
            escrows.append(e)
        except (json.JSONDecodeError, OSError):
            continue

    held = sum(e["amount"] for e in escrows if e.get("status") == "held")

    return {
        "total_credits_in_circulation": round(total_supply, 2),
        "credits_in_escrow": round(held, 2),
        "active_agents": active_agents,
        "total_escrows": len(escrows),
        "platform_revenue": get_platform_revenue()["total_revenue"],
    }
