import json
import hmac
import hashlib

from fastapi import APIRouter, Depends, Request, status
from fastapi.responses import Response
from pydantic import BaseModel, Field
from sqlalchemy.ext.asyncio import AsyncSession
from redis.asyncio import Redis

from app.dependencies import get_db, get_current_user, get_redis
from app.middleware.rate_limiter import endpoint_rate_limit
from app.modules.user.models import User
from app.modules.user.service import UserService
from app.modules.user.schema import (
    UserCreate,
    UserLogin,
    UserResponse,
    Token,
)
from app.modules.user import stripe as stripe_svc
from app.config import get_settings

router = APIRouter()


@router.post("/register", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
async def register(
    data: UserCreate,
    db: AsyncSession = Depends(get_db),
    _rate_limit: bool = Depends(endpoint_rate_limit(3, 300))
):
    """Register new user - Rate limit: 3/5min"""
    service = UserService(db)
    user = await service.create_user(data)
    return user


@router.post("/login", response_model=Token)
async def login(
    data: UserLogin,
    db: AsyncSession = Depends(get_db),
    _rate_limit: bool = Depends(endpoint_rate_limit(5, 60))
):
    """Login user - Rate limit: 5/min (prevents brute force)"""
    service = UserService(db)
    user = await service.authenticate(data.username, data.password)

    access_token = service.create_access_token(user.id, user.username)

    return Token(access_token=access_token)


# ── Account Settings ──────────────────────────────────────

@router.get("/me")
async def get_me(current_user: User = Depends(get_current_user)):
    """Get current user profile including subscription and referral info."""
    return {
        "id": current_user.id,
        "username": current_user.username,
        "email": current_user.email,
        "is_superuser": current_user.is_superuser,
        "subscription_tier": getattr(current_user, "subscription_tier", None),
        "referral_code": getattr(current_user, "referral_code", None),
        "referred_by": getattr(current_user, "referred_by", None),
        "session_ttl_hours": getattr(current_user, "session_ttl_hours", 72),
    }


class SessionTTLUpdate(BaseModel):
    hours: int = Field(..., ge=1, le=96)


@router.put("/me/session-ttl")
async def update_session_ttl(
    data: SessionTTLUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    redis: Redis = Depends(get_redis),
):
    """Update session credential TTL (1-96 hours)."""
    from sqlalchemy import select
    result = await db.execute(select(User).where(User.id == current_user.id))
    user = result.scalar_one()
    user.session_ttl_hours = data.hours
    await db.commit()
    # Invalidate user cache
    await redis.delete(f"user:{current_user.id}")
    return {"session_ttl_hours": data.hours}


# ── Stripe Subscription ──────────────────────────────────

class CheckoutRequest(BaseModel):
    tier: str = Field(..., pattern=r"^(terminal|api)$")
    referral_code: str | None = None


@router.post("/subscribe")
async def create_checkout(
    data: CheckoutRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
    _rate_limit: bool = Depends(endpoint_rate_limit(5, 60)),
):
    """Create Stripe checkout session for subscription."""
    from sqlalchemy import select
    result = await db.execute(select(User).where(User.id == current_user.id))
    user = result.scalar_one()
    return await stripe_svc.create_checkout_session(
        db, user, data.tier, data.referral_code
    )


@router.post("/billing-portal", dependencies=[Depends(endpoint_rate_limit(5, 60))])
async def billing_portal(
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Get Stripe billing portal URL for managing subscription."""
    from sqlalchemy import select
    result = await db.execute(select(User).where(User.id == current_user.id))
    user = result.scalar_one()
    return await stripe_svc.create_billing_portal(db, user)


@router.post("/stripe/webhook")
async def stripe_webhook(request: Request, db: AsyncSession = Depends(get_db)):
    """Handle Stripe webhook events. Verified via signature."""
    settings = get_settings()
    payload = await request.body()
    sig_header = request.headers.get("stripe-signature", "")

    if not settings.STRIPE_WEBHOOK_SECRET:
        return Response("Webhook secret not configured", status_code=500)

    import stripe
    stripe.api_key = settings.STRIPE_SECRET_KEY

    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, settings.STRIPE_WEBHOOK_SECRET
        )
    except (ValueError, stripe.SignatureVerificationError):
        return Response("Invalid signature", status_code=400)

    await stripe_svc.handle_webhook_event(db, event)
    return {"received": True}


# ── Referral ──────────────────────────────────────────────

@router.get("/referral/validate/{code}")
async def validate_referral_code(code: str):
    """Validate a referral code and return discount info."""
    info = stripe_svc.get_referral_info(code)
    if not info:
        return {"valid": False}
    return {"valid": True, **info}


@router.get("/referral/codes")
async def list_referral_codes():
    """List all available referral codes (public)."""
    return {
        "codes": [
            {"code": code, "owner": owner}
            for code, owner in stripe_svc.REFERRAL_CODES.items()
        ]
    }