"""
Darkroom Token Admin Router
=============================
Admin-only endpoints for deploying, minting, and managing tokens
across multiple chains. Includes blacklist/anti-bot controls.

All endpoints require X-Admin-Key header.

Routes:
  POST /api/v1/admin/tokens/deploy       — Deploy new token
  POST /api/v1/admin/tokens/mint       — Mint additional tokens
  POST /api/v1/admin/tokens/burn       — Burn tokens
  POST /api/v1/admin/tokens/transfer   — Transfer ownership
  POST /api/v1/admin/tokens/renounce   — Renounce ownership
  POST /api/v1/admin/tokens/blacklist  — Add to blacklist
  POST /api/v1/admin/tokens/unblacklist — Remove from blacklist
  GET  /api/v1/admin/tokens/list       — List all deployments
  GET  /api/v1/admin/tokens/{id}       — Get deployment details
  GET  /api/v1/admin/tokens/chains     — List supported chains
"""

import logging
import os

from fastapi import APIRouter, Body, Depends, HTTPException, Request
from pydantic import BaseModel, Field

from app.token_deployer import (
    DeployParams,
    TokenDeployerFactory,
    get_storage,
)

logger = logging.getLogger("darkroom_token_admin")

router = APIRouter(prefix="/api/v1/admin/tokens", tags=["darkroom-tokens"])


# ── Auth helper ───────────────────────────────────────────────


async def _verify_admin(request: Request):
    """Verify admin access with API key."""
    admin_key = os.getenv("ADMIN_API_KEY", "dev-key-change-me")
    key = request.headers.get("X-Admin-Key", "")
    if key != admin_key:
        raise HTTPException(status_code=401, detail="Invalid admin key")
    return True


# ── Request Models ──────────────────────────────────────────


class DeployTokenRequest(BaseModel):
    chain: str = Field(..., description="Chain: ethereum, base, bsc, solana, tron")
    name: str = Field(..., min_length=1, max_length=50)
    symbol: str = Field(..., min_length=1, max_length=10)
    decimals: int = Field(default=18, ge=0, le=18)
    initial_supply: str = Field(default="1000000")
    max_supply: str | None = None
    mintable: bool = True
    burnable: bool = True
    pausable: bool = False
    owner_address: str | None = None
    metadata_uri: str | None = None
    # Blacklist / anti-bot
    blacklist_enabled: bool = True
    blacklist_addresses: list[str] = Field(default_factory=list)
    max_wallet_limit: str | None = None
    max_tx_limit: str | None = None
    trading_enabled: bool = True
    anti_bot_delay: int = 0
    # Advanced
    tax_rate: float | None = None
    tax_recipient: str | None = None
    deflationary: bool = False


class MintRequest(BaseModel):
    deployment_id: str
    to_address: str
    amount: str


class BurnRequest(BaseModel):
    deployment_id: str
    amount: str


class TransferOwnershipRequest(BaseModel):
    deployment_id: str
    new_owner: str


class BlacklistRequest(BaseModel):
    deployment_id: str
    address: str


class SetLimitRequest(BaseModel):
    deployment_id: str
    amount: str


class TradingToggleRequest(BaseModel):
    deployment_id: str
    enabled: bool


# ── Endpoints ─────────────────────────────────────────────────


@router.get("/chains")
async def list_chains(request: Request, _=Depends(_verify_admin)):
    """List all supported chains and their configuration status."""
    chains = TokenDeployerFactory.list_supported_chains()
    return {
        "chains": chains,
        "total": len(chains),
        "configured": sum(1 for c in chains if c["configured"]),
    }


@router.post("/deploy")
async def deploy_token(request: Request, body: DeployTokenRequest, _=Depends(_verify_admin)):
    """Deploy a new token on the specified chain."""
    try:
        # Get deployer for chain
        deployer = TokenDeployerFactory.get_deployer(body.chain)

        # Build params
        params = DeployParams(
            chain=body.chain,
            name=body.name,
            symbol=body.symbol,
            decimals=body.decimals,
            initial_supply=body.initial_supply,
            max_supply=body.max_supply,
            mintable=body.mintable,
            burnable=body.burnable,
            pausable=body.pausable,
            owner_address=body.owner_address or deployer.deployer_address,
            metadata_uri=body.metadata_uri,
            blacklist_enabled=body.blacklist_enabled,
            blacklist_addresses=body.blacklist_addresses,
            max_wallet_limit=body.max_wallet_limit,
            max_tx_limit=body.max_tx_limit,
            trading_enabled=body.trading_enabled,
            anti_bot_delay=body.anti_bot_delay,
            tax_rate=body.tax_rate,
            tax_recipient=body.tax_recipient,
            deflationary=body.deflationary,
        )

        # Deploy
        deployment = await deployer.deploy_token(params)

        # Apply initial blacklist if provided
        if body.blacklist_addresses and body.blacklist_enabled:
            for addr in body.blacklist_addresses:
                try:
                    await deployer.blacklist_add(deployment.contract_address, addr)
                    logger.info(f"Blacklisted {addr} on {deployment.contract_address}")
                except Exception as e:
                    logger.warning(f"Failed to blacklist {addr}: {e}")

        # Apply max limits if set
        if body.max_wallet_limit:
            try:
                await deployer.set_max_wallet(deployment.contract_address, body.max_wallet_limit)
            except Exception as e:
                logger.warning(f"Failed to set max wallet: {e}")

        if body.max_tx_limit:
            try:
                await deployer.set_max_tx(deployment.contract_address, body.max_tx_limit)
            except Exception as e:
                logger.warning(f"Failed to set max tx: {e}")

        # Save deployment record
        storage = await get_storage()
        await storage.save(deployment)

        return {
            "success": True,
            "deployment": deployment.to_dict(),
            "explorer_url": _get_explorer_url(body.chain, deployment.contract_address),
        }

    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"Token deployment failed: {e}")
        raise HTTPException(status_code=500, detail=f"Deployment failed: {e!s}")


@router.post("/mint")
async def mint_tokens(request: Request, body: MintRequest, _=Depends(_verify_admin)):
    """Mint additional tokens for a deployed contract."""
    try:
        storage = await get_storage()
        deployment = await storage.get(body.deployment_id)
        if not deployment:
            raise HTTPException(status_code=404, detail="Deployment not found")

        if deployment.status != "deployed":
            raise HTTPException(status_code=400, detail=f"Cannot mint — status is {deployment.status}")

        deployer = TokenDeployerFactory.get_deployer(deployment.chain)
        tx_hash = await deployer.mint_tokens(deployment.contract_address, body.to_address, body.amount)

        await storage.update_status(body.deployment_id, "minting", {"last_mint_tx": tx_hash})

        return {
            "success": True,
            "tx_hash": tx_hash,
            "explorer_url": _get_explorer_url(deployment.chain, tx_hash, is_tx=True),
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Mint failed: {e}")
        raise HTTPException(status_code=500, detail=f"Mint failed: {e!s}")


@router.post("/burn")
async def burn_tokens(request: Request, body: BurnRequest, _=Depends(_verify_admin)):
    """Burn tokens from deployer balance."""
    try:
        storage = await get_storage()
        deployment = await storage.get(body.deployment_id)
        if not deployment:
            raise HTTPException(status_code=404, detail="Deployment not found")

        deployer = TokenDeployerFactory.get_deployer(deployment.chain)
        tx_hash = await deployer.burn_tokens(deployment.contract_address, body.amount)

        await storage.update_status(body.deployment_id, "burned", {"last_burn_tx": tx_hash})

        return {
            "success": True,
            "tx_hash": tx_hash,
            "explorer_url": _get_explorer_url(deployment.chain, tx_hash, is_tx=True),
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Burn failed: {e}")
        raise HTTPException(status_code=500, detail=f"Burn failed: {e!s}")


@router.post("/transfer")
async def transfer_ownership(request: Request, body: TransferOwnershipRequest, _=Depends(_verify_admin)):
    """Transfer contract ownership to a new address."""
    try:
        storage = await get_storage()
        deployment = await storage.get(body.deployment_id)
        if not deployment:
            raise HTTPException(status_code=404, detail="Deployment not found")

        deployer = TokenDeployerFactory.get_deployer(deployment.chain)
        tx_hash = await deployer.transfer_ownership(deployment.contract_address, body.new_owner)

        await storage.update_status(
            body.deployment_id,
            "ownership_transferred",
            {"new_owner": body.new_owner, "transfer_tx": tx_hash},
        )

        return {
            "success": True,
            "tx_hash": tx_hash,
            "new_owner": body.new_owner,
            "explorer_url": _get_explorer_url(deployment.chain, tx_hash, is_tx=True),
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Ownership transfer failed: {e}")
        raise HTTPException(status_code=500, detail=f"Transfer failed: {e!s}")


@router.post("/renounce")
async def renounce_ownership(request: Request, body: dict = Body(...), _=Depends(_verify_admin)):
    """Renounce contract ownership (make immutable). WARNING: Irreversible."""
    deployment_id = body.get("deployment_id", "")

    try:
        storage = await get_storage()
        deployment = await storage.get(deployment_id)
        if not deployment:
            raise HTTPException(status_code=404, detail="Deployment not found")

        deployer = TokenDeployerFactory.get_deployer(deployment.chain)
        tx_hash = await deployer.renounce_ownership(deployment.contract_address)

        await storage.update_status(deployment_id, "ownership_renounced", {"renounce_tx": tx_hash})

        return {
            "success": True,
            "tx_hash": tx_hash,
            "warning": "Ownership renounced. Contract is now immutable.",
            "explorer_url": _get_explorer_url(deployment.chain, tx_hash, is_tx=True),
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Renounce failed: {e}")
        raise HTTPException(status_code=500, detail=f"Renounce failed: {e!s}")


# ── Blacklist / Anti-Bot Endpoints ────────────────────────────


@router.post("/blacklist")
async def blacklist_add(request: Request, body: BlacklistRequest, _=Depends(_verify_admin)):
    """Add an address to the token blacklist."""
    try:
        storage = await get_storage()
        deployment = await storage.get(body.deployment_id)
        if not deployment:
            raise HTTPException(status_code=404, detail="Deployment not found")

        deployer = TokenDeployerFactory.get_deployer(deployment.chain)
        tx_hash = await deployer.blacklist_add(deployment.contract_address, body.address)

        return {
            "success": True,
            "tx_hash": tx_hash,
            "address": body.address,
            "action": "blacklisted",
            "explorer_url": _get_explorer_url(deployment.chain, tx_hash, is_tx=True),
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Blacklist add failed: {e}")
        raise HTTPException(status_code=500, detail=f"Blacklist failed: {e!s}")


@router.post("/unblacklist")
async def blacklist_remove(request: Request, body: BlacklistRequest, _=Depends(_verify_admin)):
    """Remove an address from the token blacklist."""
    try:
        storage = await get_storage()
        deployment = await storage.get(body.deployment_id)
        if not deployment:
            raise HTTPException(status_code=404, detail="Deployment not found")

        deployer = TokenDeployerFactory.get_deployer(deployment.chain)
        tx_hash = await deployer.blacklist_remove(deployment.contract_address, body.address)

        return {
            "success": True,
            "tx_hash": tx_hash,
            "address": body.address,
            "action": "unblacklisted",
            "explorer_url": _get_explorer_url(deployment.chain, tx_hash, is_tx=True),
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Unblacklist failed: {e}")
        raise HTTPException(status_code=500, detail=f"Unblacklist failed: {e!s}")


@router.get("/blacklist/check")
async def check_blacklist(request: Request, deployment_id: str, address: str, _=Depends(_verify_admin)):
    """Check if an address is blacklisted."""
    try:
        storage = await get_storage()
        deployment = await storage.get(deployment_id)
        if not deployment:
            raise HTTPException(status_code=404, detail="Deployment not found")

        deployer = TokenDeployerFactory.get_deployer(deployment.chain)
        is_blacklisted = await deployer.is_blacklisted(deployment.contract_address, address)

        return {
            "address": address,
            "is_blacklisted": is_blacklisted,
            "contract": deployment.contract_address,
            "chain": deployment.chain,
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Blacklist check failed: {e}")
        raise HTTPException(status_code=500, detail=f"Check failed: {e!s}")


@router.post("/trading")
async def set_trading(request: Request, body: TradingToggleRequest, _=Depends(_verify_admin)):
    """Enable or disable trading for the token."""
    try:
        storage = await get_storage()
        deployment = await storage.get(body.deployment_id)
        if not deployment:
            raise HTTPException(status_code=404, detail="Deployment not found")

        deployer = TokenDeployerFactory.get_deployer(deployment.chain)
        tx_hash = await deployer.set_trading_enabled(deployment.contract_address, body.enabled)

        return {
            "success": True,
            "tx_hash": tx_hash,
            "trading_enabled": body.enabled,
            "explorer_url": _get_explorer_url(deployment.chain, tx_hash, is_tx=True),
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Trading toggle failed: {e}")
        raise HTTPException(status_code=500, detail=f"Toggle failed: {e!s}")


@router.post("/max-wallet")
async def set_max_wallet(request: Request, body: SetLimitRequest, _=Depends(_verify_admin)):
    """Set maximum wallet holding limit."""
    try:
        storage = await get_storage()
        deployment = await storage.get(body.deployment_id)
        if not deployment:
            raise HTTPException(status_code=404, detail="Deployment not found")

        deployer = TokenDeployerFactory.get_deployer(deployment.chain)
        tx_hash = await deployer.set_max_wallet(deployment.contract_address, body.amount)

        return {
            "success": True,
            "tx_hash": tx_hash,
            "max_wallet": body.amount,
            "explorer_url": _get_explorer_url(deployment.chain, tx_hash, is_tx=True),
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Max wallet set failed: {e}")
        raise HTTPException(status_code=500, detail=f"Set failed: {e!s}")


@router.post("/max-tx")
async def set_max_tx(request: Request, body: SetLimitRequest, _=Depends(_verify_admin)):
    """Set maximum transaction limit."""
    try:
        storage = await get_storage()
        deployment = await storage.get(body.deployment_id)
        if not deployment:
            raise HTTPException(status_code=404, detail="Deployment not found")

        deployer = TokenDeployerFactory.get_deployer(deployment.chain)
        tx_hash = await deployer.set_max_tx(deployment.contract_address, body.amount)

        return {
            "success": True,
            "tx_hash": tx_hash,
            "max_tx": body.amount,
            "explorer_url": _get_explorer_url(deployment.chain, tx_hash, is_tx=True),
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Max tx set failed: {e}")
        raise HTTPException(status_code=500, detail=f"Set failed: {e!s}")


# ── Query Endpoints ───────────────────────────────────────────


@router.get("/list")
async def list_deployments(request: Request, chain: str | None = None, limit: int = 100, _=Depends(_verify_admin)):
    """List all token deployments."""
    try:
        storage = await get_storage()
        deployments = await storage.list_all(chain=chain, limit=limit)

        return {
            "deployments": [d.to_dict() for d in deployments],
            "total": len(deployments),
            "chain_filter": chain,
        }

    except Exception as e:
        logger.error(f"List failed: {e}")
        raise HTTPException(status_code=500, detail=f"List failed: {e!s}")


@router.get("/{deployment_id}")
async def get_deployment(request: Request, deployment_id: str, _=Depends(_verify_admin)):
    """Get deployment details by ID."""
    try:
        storage = await get_storage()
        deployment = await storage.get(deployment_id)
        if not deployment:
            raise HTTPException(status_code=404, detail="Deployment not found")

        # Get on-chain info
        try:
            deployer = TokenDeployerFactory.get_deployer(deployment.chain)
            token_info = await deployer.get_token_info(deployment.contract_address)
        except Exception:
            token_info = {}

        return {
            "deployment": deployment.to_dict(),
            "on_chain_info": token_info,
            "explorer_url": _get_explorer_url(deployment.chain, deployment.contract_address),
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Get deployment failed: {e}")
        raise HTTPException(status_code=500, detail=f"Get failed: {e!s}")


@router.get("/{deployment_id}/balance/{wallet_address}")
async def get_balance(request: Request, deployment_id: str, wallet_address: str, _=Depends(_verify_admin)):
    """Get token balance for a specific wallet."""
    try:
        storage = await get_storage()
        deployment = await storage.get(deployment_id)
        if not deployment:
            raise HTTPException(status_code=404, detail="Deployment not found")

        deployer = TokenDeployerFactory.get_deployer(deployment.chain)
        balance = await deployer.get_balance(deployment.contract_address, wallet_address)

        return {
            "wallet": wallet_address,
            "balance": balance,
            "contract": deployment.contract_address,
            "chain": deployment.chain,
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Balance check failed: {e}")
        raise HTTPException(status_code=500, detail=f"Balance check failed: {e!s}")


# ── Helpers ───────────────────────────────────────────────────


def _get_explorer_url(chain: str, address_or_tx: str, is_tx: bool = False) -> str:
    """Get block explorer URL for a chain."""
    explorers = {
        "ethereum": "https://etherscan.io",
        "base": "https://basescan.org",
        "bsc": "https://bscscan.com",
        "solana": "https://solscan.io",
        "tron": "https://tronscan.org/#",
    }
    base = explorers.get(chain, "")
    if not base:
        return ""

    if chain == "tron":
        path = "transaction" if is_tx else "contract"
        return f"{base}/{path}/{address_or_tx}"

    path = "tx" if is_tx else "address"
    return f"{base}/{path}/{address_or_tx}"
