#!/usr/bin/env python3
"""
Bulletin Board & Badge API Router
Refactored to use supabase_service for clean, typed database access.
Includes bot registration, fee tracking, and bot-specific endpoints.
Uses direct Supabase REST API via httpx (no supabase-py dependency issues).
"""

import logging
import os
from datetime import datetime

import httpx
from fastapi import APIRouter, Depends, HTTPException, Query, Request
from pydantic import BaseModel

logger = logging.getLogger(__name__)

import contextlib

from app.services.supabase_service import (
    award_badge,
    create_alert,
    create_bulletin_post,
    get_alerts,
    get_badges,
    get_bulletin_posts,
    get_profile,
    get_user_badges,
    vote_post,
)


# Lazy auth dependency — avoids importing passlib+jose+bcrypt at module load
async def _require_public_profile(request: Request):
    from app.auth import require_public_profile

    return await require_public_profile(request)


router = APIRouter(prefix="/api/v1/bulletin")

# ── Supabase REST helpers ──────────────────────────────────────


def _sb():
    """Return (url, headers) for direct Supabase REST API."""
    key = os.environ["SUPABASE_SERVICE_KEY"]
    url = os.environ["SUPABASE_URL"]
    return url, {
        "apikey": key,
        "Authorization": f"Bearer {key}",
        "Content-Type": "application/json",
        "Prefer": "return=representation",
    }


def _sb_get(table: str, params: dict | None = None) -> list:
    url, headers = _sb()
    r = httpx.get(f"{url}/rest/v1/{table}", headers=headers, params=params, timeout=10)
    return r.json() if r.status_code == 200 else []


def _sb_post(table: str, data: dict) -> list:
    url, headers = _sb()
    r = httpx.post(f"{url}/rest/v1/{table}", headers=headers, json=data, timeout=10)
    return r.json() if r.status_code in (200, 201) else []


def _sb_patch(table: str, data: dict, match: dict) -> list:
    url, headers = _sb()
    params = "&".join(f"{k}=eq.{v}" for k, v in match.items())
    r = httpx.patch(f"{url}/rest/v1/{table}?{params}", headers=headers, json=data, timeout=10)
    return r.json() if r.status_code == 200 else []


# ── Models ──────────────────────────────────────────────────


class BulletinPostIn(BaseModel):
    title: str
    content: str
    author_id: str
    category: str = "discussion"
    chain: str | None = None
    risk_score: int | None = None
    tags: list[str] | None = None
    source: str | None = None
    is_bot: bool = False
    bot_id: str | None = None


class AlertIn(BaseModel):
    title: str
    description: str
    severity: str = "medium"
    alert_type: str = "security"
    chain: str | None = None
    token: str | None = None
    wallet: str | None = None
    amount_usd: float | None = None
    user_id: str | None = None


class BotRegistrationIn(BaseModel):
    owner_id: str
    bot_name: str
    bot_type: str = "general"
    fee_paid: float = 0
    fee_currency: str = "usdc"
    rules: list[str] = []
    allowed_categories: list[str] = []


# ── Bulletin Posts ──────────────────────────────────────────


@router.get("/latest")
async def latest_posts(
    category: str = Query(None),
    sort: str = Query("created_at.desc"),
    limit: int = Query(20, ge=1, le=100),
    include_bots: bool = Query(True),
):
    posts = await get_bulletin_posts(category=category, sort=sort, limit=limit)
    for post in posts:
        if not include_bots and post.get("is_bot"):
            continue
        if post.get("author_id"):
            profile = await get_profile(post["author_id"])
            if profile:
                post["author"] = {
                    "username": profile.get("username", profile.get("display_name", "Unknown")),
                    "avatar_url": profile.get("avatar_url", ""),
                    "reputation": profile.get("reputation_score", 0),
                    "level": profile.get("level", 1),
                    "is_bot": profile.get("is_bot", False),
                }
    if not include_bots:
        posts = [p for p in posts if not p.get("is_bot")]
    return {"posts": posts, "total": len(posts)}


@router.post("/posts")
async def create_post(post: BulletinPostIn, user: dict = Depends(_require_public_profile)):
    result = await create_bulletin_post(
        title=post.title,
        content=post.content,
        author_id=user["id"],
        category=post.category,
        chain=post.chain,
        tags=post.tags,
        risk_score=post.risk_score,
        source=post.source,
    )
    if not result:
        raise HTTPException(status_code=500, detail="Failed to create post")
    if post.is_bot and result.get("id"):
        with contextlib.suppress(Exception):
            _sb_patch("bulletin_posts", {"is_bot": True, "bot_id": post.bot_id}, {"id": result["id"]})
    return result


@router.post("/posts/{post_id}/vote")
async def vote(post_id: int, vote_type: str = Query(..., pattern="^(up|down)$")):
    ok = await vote_post(post_id, vote_type)
    if not ok:
        raise HTTPException(status_code=404, detail="Post not found or vote failed")
    return {"status": "ok", "post_id": post_id, "vote": vote_type}


class CommentIn(BaseModel):
    content: str


@router.post("/posts/{post_id}/comments")
async def create_comment(post_id: int, comment: CommentIn, user: dict = Depends(_require_public_profile)):
    """Create a comment on a bulletin post. Requires public profile."""
    # Store comment in Supabase or Redis (using simple dict for now if not in supabase_service)
    # For now, we'll just return success and let the frontend handle local state,
    # or we can add it to supabase_service if needed.
    # Let's use a simple in-memory store or supabase if available.
    # Since supabase_service doesn't have create_comment, we'll add a basic implementation.
    try:
        result = _sb_post(
            "bulletin_comments",
            {
                "post_id": post_id,
                "user_id": user["id"],
                "content": comment.content,
                "created_at": datetime.utcnow().isoformat(),
            },
        )
        if not result:
            raise HTTPException(status_code=500, detail="Failed to create comment")
        return {"status": "ok", "comment": result[0]}
    except Exception as e:
        # Fallback if table doesn't exist yet
        logger.warning(f"Comment creation failed (table may not exist): {e}")
        return {
            "status": "ok",
            "comment": {
                "id": "temp",
                "content": comment.content,
                "user_id": user["id"],
                "created_at": datetime.utcnow().isoformat(),
            },
        }


@router.get("/posts/{post_id}/comments")
async def get_comments(post_id: int):
    """Get comments for a bulletin post."""
    try:
        comments = _sb_get("bulletin_comments", {"post_id": f"eq.{post_id}", "order": "created_at.asc"})
        return {"comments": comments}
    except Exception:
        return {"comments": []}


# ── Bot Endpoints ───────────────────────────────────────────

BOT_FEE_USD = 1.00  # $1 fee for bots to participate


@router.post("/bots/register")
async def register_bot(bot: BotRegistrationIn):
    """Register a new bot account. Bot must pay a fee to participate."""
    # Create the bot profile
    try:
        profiles = _sb_post(
            "profiles",
            {
                "username": bot.bot_name,
                "is_bot": True,
                "bot_owner": bot.owner_id,
                "bot_fee_paid": bot.fee_paid,
                "bot_rules": bot.rules,
                "role": "BOT",
                "tier": "FREE",
            },
        )
        if not profiles:
            raise HTTPException(status_code=500, detail="Failed to create bot profile")
        bot_profile = profiles[0]
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Bot profile creation failed: {e}")

    # Create bot registration record
    try:
        regs = _sb_post(
            "bot_registrations",
            {
                "bot_user_id": bot_profile["id"],
                "owner_user_id": bot.owner_id,
                "bot_name": bot.bot_name,
                "bot_type": bot.bot_type,
                "fee_paid": bot.fee_paid,
                "fee_currency": bot.fee_currency,
                "rules": bot.rules,
                "allowed_categories": bot.allowed_categories,
                "status": "active" if bot.fee_paid >= BOT_FEE_USD else "pending_fee",
            },
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Bot registration failed: {e}")

    # Log the fee payment
    if bot.fee_paid > 0:
        with contextlib.suppress(Exception):
            _sb_post(
                "bot_fee_log",
                {
                    "bot_id": bot_profile["id"],
                    "amount": bot.fee_paid,
                    "currency": bot.fee_currency,
                    "reason": "registration_fee",
                },
            )

    return {
        "bot_profile": bot_profile,
        "registration": regs[0] if regs else None,
        "fee_required": BOT_FEE_USD,
        "fee_paid": bot.fee_paid,
        "fee_remaining": max(0, BOT_FEE_USD - bot.fee_paid),
        "status": "active" if bot.fee_paid >= BOT_FEE_USD else "pending_fee",
    }


@router.get("/bots")
async def list_bots(status: str = Query(None), limit: int = Query(50)):
    """List all registered bots."""
    params: dict = {
        "select": "*,profiles:bot_user_id(username,is_bot,level,reputation_score)",
        "limit": str(limit),
        "order": "created_at.desc",
    }
    if status:
        params["status"] = f"eq.{status}"
    result = _sb_get("bot_registrations", params)
    return {"bots": result, "total": len(result)}


@router.get("/bots/{bot_id}/fee-status")
async def bot_fee_status(bot_id: str):
    """Check a bot's fee payment status."""
    reg = _sb_get("bot_registrations", {"bot_user_id": f"eq.{bot_id}", "limit": "1"})
    if not reg:
        raise HTTPException(status_code=404, detail="Bot not registered")
    registration = reg[0]

    fees = _sb_get("bot_fee_log", {"bot_id": f"eq.{bot_id}", "order": "created_at.desc"})
    total_paid = sum(f.get("amount", 0) for f in fees)
    return {
        "bot_id": bot_id,
        "total_paid": total_paid,
        "fee_required": BOT_FEE_USD,
        "fee_remaining": max(0, BOT_FEE_USD - total_paid),
        "status": registration["status"],
        "fee_history": fees,
    }


@router.post("/bots/{bot_id}/pay-fee")
async def pay_bot_fee(bot_id: str, amount: float, tx_hash: str | None = None, currency: str = "usdc"):
    """Record a bot fee payment."""
    try:
        _sb_post(
            "bot_fee_log",
            {
                "bot_id": bot_id,
                "amount": amount,
                "currency": currency,
                "tx_hash": tx_hash,
                "reason": "participation_fee",
            },
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Fee logging failed: {e}")

    fees = _sb_get("bot_fee_log", {"bot_id": f"eq.{bot_id}", "select": "amount"})
    total_paid = sum(f.get("amount", 0) for f in fees)
    if total_paid >= BOT_FEE_USD:
        _sb_patch("bot_registrations", {"status": "active"}, {"bot_user_id": bot_id})
        _sb_patch("profiles", {"bot_fee_paid": total_paid}, {"id": bot_id})

    return {
        "amount_paid": amount,
        "total_paid": total_paid,
        "fee_required": BOT_FEE_USD,
        "status": "active" if total_paid >= BOT_FEE_USD else "pending_fee",
    }


@router.post("/bots/{bot_id}/post")
async def bot_create_post(bot_id: str, post: BulletinPostIn):
    """Bot creates a post — must be registered and fee-paid."""
    reg = _sb_get("bot_registrations", {"bot_user_id": f"eq.{bot_id}", "status": "eq.active", "limit": "1"})
    if not reg:
        raise HTTPException(status_code=403, detail="Bot not registered or fee not paid")

    registration = reg[0]
    if registration.get("allowed_categories") and post.category not in registration["allowed_categories"]:
        raise HTTPException(status_code=403, detail=f"Bot not allowed to post in category: {post.category}")

    post.is_bot = True
    post.bot_id = bot_id
    post.source = post.source or f"bot:{registration['bot_name']}"

    result = await create_bulletin_post(
        title=post.title,
        content=post.content,
        author_id=post.author_id,
        category=post.category,
        chain=post.chain,
        tags=post.tags,
        risk_score=post.risk_score,
        source=post.source,
    )
    if not result:
        raise HTTPException(status_code=500, detail="Failed to create post")

    with contextlib.suppress(Exception):
        _sb_patch("bulletin_posts", {"is_bot": True, "bot_id": bot_id}, {"id": result["id"]})
    return result


# ── Reports & Moderation ──────────────────────────────────────


class ReportIn(BaseModel):
    post_id: int
    reporter_id: str
    reason: str
    details: str | None = None
    category: str = "other"  # spam, abuse, misinformation, scam, bot_violation, other


class ModerationActionIn(BaseModel):
    admin_id: str
    action: str  # remove, lock, pin, unpin, unlock, restore, ban_user
    target_type: str  # post, user, bot
    target_id: str
    reason: str | None = None


@router.post("/reports")
async def create_report(report: ReportIn):
    """Submit a report on a post."""
    result = _sb_post(
        "bulletin_reports",
        {
            "post_id": report.post_id,
            "reporter_id": report.reporter_id,
            "reason": report.reason,
            "details": report.details,
            "category": report.category,
            "status": "open",
        },
    )
    if not result:
        raise HTTPException(status_code=500, detail="Failed to create report")
    return result[0]


@router.get("/reports")
async def list_reports(status: str = Query(None), limit: int = Query(50, ge=1, le=200)):
    """List reports (admin view)."""
    params: dict = {"order": "created_at.desc", "limit": str(limit)}
    if status:
        params["status"] = f"eq.{status}"
    result = _sb_get("bulletin_reports", params)
    return {"reports": result, "total": len(result)}


@router.post("/moderate")
async def moderate(moderation: ModerationActionIn):
    """Take a moderation action."""
    # Log the action
    _sb_post(
        "bulletin_moderation_log",
        {
            "admin_id": moderation.admin_id,
            "action": moderation.action,
            "target_type": moderation.target_type,
            "target_id": moderation.target_id,
            "reason": moderation.reason,
        },
    )

    # Apply the action
    if moderation.target_type == "post":
        match = {"id": moderation.target_id}
        if moderation.action == "remove":
            _sb_patch("bulletin_posts", {"removed": True, "removed_reason": moderation.reason}, match)
        elif moderation.action == "restore":
            _sb_patch("bulletin_posts", {"removed": False, "removed_reason": None}, match)
        elif moderation.action == "pin":
            _sb_patch("bulletin_posts", {"pinned": True}, match)
        elif moderation.action == "unpin":
            _sb_patch("bulletin_posts", {"pinned": False}, match)
        elif moderation.action == "lock":
            _sb_patch("bulletin_posts", {"locked": True}, match)
        elif moderation.action == "unlock":
            _sb_patch("bulletin_posts", {"locked": False}, match)

    elif moderation.target_type == "bot":
        if moderation.action == "ban_user":
            _sb_patch("bot_registrations", {"status": "banned"}, {"bot_user_id": moderation.target_id})

    return {
        "status": "ok",
        "action": moderation.action,
        "target": f"{moderation.target_type}:{moderation.target_id}",
    }


@router.get("/moderation/log")
async def moderation_log(limit: int = Query(50)):
    """View moderation log."""
    result = _sb_get("bulletin_moderation_log", {"order": "created_at.desc", "limit": str(limit)})
    return {"log": result, "total": len(result)}


# ── Badges ──────────────────────────────────────────────────


@router.get("/badges")
async def list_badges(rarity: str = Query(None)):
    return await get_badges(rarity=rarity)


@router.get("/badges/{user_id}")
async def user_badges(user_id: str):
    badges = await get_user_badges(user_id)
    return badges


@router.post("/badges/award")
async def award(badge_id: str, user_id: str, earned_via: str = "auto"):
    result = await award_badge(user_id, badge_id, earned_via)
    if not result:
        raise HTTPException(status_code=500, detail="Failed to award badge")
    return result


# ── Alerts ──────────────────────────────────────────────────


@router.get("/alerts")
async def list_alerts(severity: str = Query(None), limit: int = Query(50, ge=1, le=200)):
    alerts = await get_alerts(severity=severity, limit=limit)
    return {"alerts": alerts, "total": len(alerts)}


@router.post("/alerts")
async def submit_alert(alert: AlertIn):
    result = await create_alert(
        title=alert.title,
        description=alert.description,
        severity=alert.severity,
        alert_type=alert.alert_type,
        chain=alert.chain,
        token=alert.token,
        wallet=alert.wallet,
        amount_usd=alert.amount_usd,
        user_id=alert.user_id,
    )
    if not result:
        raise HTTPException(status_code=500, detail="Failed to create alert")
    return result


# ── Stats ──────────────────────────────────────────────────


@router.get("/stats")
async def community_stats():
    """Get aggregate community stats from Supabase."""
    total_posts = 0
    total_users = 0
    total_bots = 0
    total_alerts = 0

    try:
        posts = _sb_get("bulletin_posts", {"select": "id", "limit": "1000"})
        total_posts = len(posts)
    except Exception:
        pass

    try:
        profiles = _sb_get("profiles", {"select": "id", "limit": "1000"})
        total_users = len(profiles)
    except Exception:
        pass

    try:
        bots = _sb_get("profiles", {"select": "id", "is_bot": "eq.true", "limit": "100"})
        total_bots = len(bots)
    except Exception:
        pass

    try:
        alerts = _sb_get("alerts", {"select": "id", "limit": "500"})
        total_alerts = len(alerts)
    except Exception:
        pass

    return {
        "total_posts": total_posts,
        "total_users": total_users,
        "total_bots": total_bots,
        "total_alerts": total_alerts,
        "bot_fee_required_usd": BOT_FEE_USD,
    }


# ── Health ──────────────────────────────────────────────────


@router.get("/health")
async def health():
    from app.services.supabase_service import check_health

    return await check_health()
