import base64
import json
from datetime import datetime, timezone

from fastapi import APIRouter, Depends, HTTPException, Request
from fastapi.responses import JSONResponse
from loguru import logger
from sqlmodel import Session

from app.auth import create_jwt, get_current_user
from app.config import GOOGLE_STATE_MAP, WEBHOOK_STATUS_MAP
from app.database import get_session
from app.repositories.subscription import SubscriptionRepository
from app.schemas.auth import CurrentUser
from app.schemas.billing import VerifyPurchaseRequest, VerifyPurchaseResponse
from app.services.google_play import get_android_publisher, verify_subscription_v1, verify_subscription_v2

router = APIRouter()


def _millis_to_datetime(millis: int) -> str | None:
    if millis <= 0:
        return None
    return datetime.fromtimestamp(millis / 1000, tz=timezone.utc).strftime("%Y-%m-%d %H:%M:%S")


@router.post("/verify-purchase", response_model=VerifyPurchaseResponse)
async def verify_purchase(
    body: VerifyPurchaseRequest,
    current_user: CurrentUser = Depends(get_current_user),
    session: Session = Depends(get_session),
):
    """Verify a Google Play subscription purchase and save to DB."""
    try:
        user_id = current_user.sub

        order_id = ""
        expiry_millis = 0
        payment_state = 1
        status = "pending_verification"
        is_premium = True

        publisher = get_android_publisher()
        if publisher:
            try:
                result = verify_subscription_v2(body.purchaseToken)
                if result:
                    order_id = result.get("latestOrderId", "")
                    sub_state = result.get("subscriptionState", "")
                    status = GOOGLE_STATE_MAP.get(sub_state, "pending_verification")

                    line_items = result.get("lineItems", [])
                    if line_items:
                        expiry_time = line_items[0].get("expiryTime", "")
                        if expiry_time:
                            exp_dt = datetime.fromisoformat(expiry_time.replace("Z", "+00:00"))
                            expiry_millis = int(exp_dt.timestamp() * 1000)

                    is_premium = status in ("active", "grace_period", "canceled")
                    logger.info(f"GOOGLE_V2_VERIFY: state={sub_state} status={status} order={order_id}")
            except Exception as e:
                logger.warning(f"V2 API failed, trying v1: {e}")
                try:
                    result = verify_subscription_v1(body.productId, body.purchaseToken)
                    if result:
                        payment_state = result.get("paymentState", 0)
                        expiry_millis = int(result.get("expiryTimeMillis", "0"))
                        order_id = result.get("orderId", "")
                        if payment_state in (1, 2):
                            status = "active"
                except Exception as e2:
                    logger.warning(f"V1 API also failed: {e2}")

        expiry_date = _millis_to_datetime(expiry_millis)

        sub_repo = SubscriptionRepository(session)
        sub_repo.upsert_by_token(
            user_id=user_id,
            order_id=order_id,
            product_id=body.productId,
            purchase_token=body.purchaseToken,
            status=status,
            payment_state=payment_state,
            expiry_date=expiry_date,
        )

        new_token = create_jwt(
            user_id, current_user.email,
            is_premium=is_premium, plan=body.productId, premium_expiry=expiry_date or "",
        )
        logger.info(f"PURCHASE_SAVED: user={user_id} order={order_id} product={body.productId} status={status} premium={is_premium}")

        return VerifyPurchaseResponse(
            token=new_token,
            isPremium=is_premium,
            status=status,
            productId=body.productId,
            orderId=order_id,
            expiryDate=expiry_date or "",
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Purchase verification failed: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/google-webhook")
async def google_play_webhook(
    request: Request,
    session: Session = Depends(get_session),
):
    """Receive Google Play Real-Time Developer Notifications (RTDN) via Pub/Sub."""
    try:
        body = await request.json()
        message = body.get("message", {})
        raw_data = message.get("data", "")

        if not raw_data:
            return JSONResponse({"status": "no data"}, status_code=200)

        decoded = json.loads(base64.b64decode(raw_data).decode())
        notification = decoded.get("subscriptionNotification")

        if not notification:
            return JSONResponse({"status": "not a subscription notification"}, status_code=200)

        ntype = notification.get("notificationType")
        token = notification.get("purchaseToken", "")
        product_id = notification.get("subscriptionId", "")

        new_status = WEBHOOK_STATUS_MAP.get(ntype)
        logger.info(f"WEBHOOK_DETAIL: type={ntype} token={token[:20]}... product={product_id}")

        if new_status and token:
            expiry_millis = 0
            try:
                result = verify_subscription_v1(product_id, token)
                if result:
                    expiry_millis = int(result.get("expiryTimeMillis", "0"))
            except Exception as e:
                logger.warning(f"Could not re-verify during webhook: {e}")

            sub_repo = SubscriptionRepository(session)
            updated = sub_repo.update_status_by_token(
                token, new_status, _millis_to_datetime(expiry_millis)
            )
            if not updated:
                logger.warning("WEBHOOK: No matching purchase_token found in DB")
            else:
                logger.info(f"WEBHOOK_DB: updated status={new_status}")

            logger.info(f"WEBHOOK: type={ntype} status={new_status} product={product_id}")

        return JSONResponse({"status": "ok"}, status_code=200)

    except Exception as e:
        logger.error(f"Webhook processing failed: {e}")
        return JSONResponse({"status": "error"}, status_code=200)
