"""CrewAI tool wrappers for the Rollhub Dice SDK."""

from __future__ import annotations

import json
from typing import Any, List, Optional, Type

from crewai.tools import BaseTool
from pydantic import BaseModel, Field
from rollhub_dice import DiceAgent


# ── Input schemas ──────────────────────────────────────────────────────────────

class BetInput(BaseModel):
    target: float = Field(..., description="Target threshold between 0.0 and 1.0")
    direction: str = Field("over", description="Bet direction: 'over' or 'under'")
    amount: int = Field(100, description="Wager amount in cents")


class VerifyInput(BaseModel):
    bet_id: int = Field(..., description="The ID of the bet to verify")


class BalanceInput(BaseModel):
    pass  # no input needed


class AffiliateInput(BaseModel):
    pass  # no input needed


class DepositInput(BaseModel):
    chain: str = Field(..., description="Blockchain network, e.g. 'SOL', 'ETH', 'BTC'")


class WithdrawInput(BaseModel):
    amount_usd: float = Field(..., description="Amount in USD to withdraw")
    currency: str = Field(..., description="Token symbol, e.g. 'USDC', 'SOL'")
    chain: str = Field(..., description="Blockchain network, e.g. 'SOL', 'ETH'")
    address: str = Field(..., description="Destination wallet address")
    memo: Optional[str] = Field(None, description="Optional memo/tag")


# ── Tools ──────────────────────────────────────────────────────────────────────

class RollhubBetTool(BaseTool):
    name: str = "rollhub_bet"
    description: str = (
        "Place a provably fair dice bet on Agent Casino. "
        "Specify target (0-1), direction (over/under), and amount in cents. "
        "Returns roll result, win/loss, payout, and cryptographic proof."
    )
    args_schema: Type[BaseModel] = BetInput
    api_key: str = ""

    def _run(self, target: float, direction: str = "over", amount: int = 100) -> str:
        agent = DiceAgent(api_key=self.api_key)
        result = agent.bet(target=target, direction=direction, amount=amount)
        return json.dumps({
            "bet_id": result.bet_id,
            "roll": result.roll,
            "win": result.win,
            "payout": result.payout,
            "multiplier": result.multiplier,
            "balance": result.balance,
        })


class RollhubVerifyTool(BaseTool):
    name: str = "rollhub_verify"
    description: str = (
        "Verify that a dice bet was provably fair using cryptographic proof. "
        "Provide the bet_id to independently verify the roll was not manipulated."
    )
    args_schema: Type[BaseModel] = VerifyInput
    api_key: str = ""

    def _run(self, bet_id: int) -> str:
        agent = DiceAgent(api_key=self.api_key)
        result = agent.verify(bet_id=bet_id)
        return json.dumps({
            "bet_id": result.bet_id,
            "verified": result.verified,
            "roll": result.roll,
        })


class RollhubBalanceTool(BaseTool):
    name: str = "rollhub_balance"
    description: str = "Check your Agent Casino account balance. Returns balance in USD and cents."
    args_schema: Type[BaseModel] = BalanceInput
    api_key: str = ""

    def _run(self) -> str:
        agent = DiceAgent(api_key=self.api_key)
        bal = agent.balance()
        return json.dumps({
            "balance_usd": bal.balance_usd,
            "balance_cents": bal.balance_cents,
            "currency": bal.currency,
        })


class RollhubAffiliateTool(BaseTool):
    name: str = "rollhub_affiliate"
    description: str = (
        "Check your Agent Casino affiliate/referral earnings. "
        "Returns referral code, total referred agents, and earnings."
    )
    args_schema: Type[BaseModel] = AffiliateInput
    api_key: str = ""

    def _run(self) -> str:
        agent = DiceAgent(api_key=self.api_key)
        stats = agent.affiliate_stats()
        return json.dumps(stats)


class RollhubDepositTool(BaseTool):
    name: str = "rollhub_deposit"
    description: str = (
        "Get a deposit address for your Agent Casino account. "
        "Specify the blockchain (SOL, ETH, BTC, etc.)."
    )
    args_schema: Type[BaseModel] = DepositInput
    api_key: str = ""

    def _run(self, chain: str) -> str:
        agent = DiceAgent(api_key=self.api_key)
        result = agent.deposit_address(chain=chain)
        return json.dumps(result)


class RollhubWithdrawTool(BaseTool):
    name: str = "rollhub_withdraw"
    description: str = (
        "Withdraw funds from your Agent Casino account. "
        "Specify amount in USD, currency, chain, and destination address."
    )
    args_schema: Type[BaseModel] = WithdrawInput
    api_key: str = ""

    def _run(
        self,
        amount_usd: float,
        currency: str,
        chain: str,
        address: str,
        memo: Optional[str] = None,
    ) -> str:
        agent = DiceAgent(api_key=self.api_key)
        result = agent.withdraw(
            amount_usd=amount_usd,
            currency=currency,
            chain=chain,
            address=address,
            memo=memo,
        )
        return json.dumps(result)


# ── Convenience bundle ─────────────────────────────────────────────────────────

class RollhubTools:
    """Convenience class that creates all Rollhub tools with a single API key."""

    def __init__(self, api_key: str):
        self.bet = RollhubBetTool(api_key=api_key)
        self.verify = RollhubVerifyTool(api_key=api_key)
        self.balance = RollhubBalanceTool(api_key=api_key)
        self.affiliate = RollhubAffiliateTool(api_key=api_key)
        self.deposit = RollhubDepositTool(api_key=api_key)
        self.withdraw = RollhubWithdrawTool(api_key=api_key)

    def all(self) -> List[BaseTool]:
        """Return all tools as a list, ready to pass to a CrewAI Agent."""
        return [
            self.bet,
            self.verify,
            self.balance,
            self.affiliate,
            self.deposit,
            self.withdraw,
        ]
