"""
Cart Plugin merchant-facing endpoints.
All routes require an authenticated merchant JWT.
"""
from __future__ import annotations

import logging
from typing import Optional

from fastapi import APIRouter, Depends, Query, status
from sqlalchemy.orm import Session

from src.core.database import get_db
from src.core.exceptions import APIException, NotFoundError
from src.apps.auth.utils.auth import get_current_merchant
from src.apps.cart_plugin import crud as cart_crud
from src.apps.cart_plugin import services as cart_services
from src.apps.cart_plugin.schemas.cart_schemas import (
    CartSessionDetailResponse,
    CartSessionListResponse,
    CartSessionSummary,
    CreateWidgetKeyRequest,
    UpdateWidgetKeyRequest,
    WidgetKeyCreateResponse,
    WidgetKeyListResponse,
    WidgetKeyResponse,
)

router = APIRouter()
logger = logging.getLogger(__name__)


# ─── Widget key endpoints ─────────────────────────────────────────────────────

@router.get("/widget-keys", response_model=WidgetKeyListResponse)
async def list_widget_keys(
    merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
):
    """List all non-revoked widget keys for the authenticated merchant."""
    keys = cart_crud.get_widget_keys_for_merchant(db, merchant.id)
    return {"items": keys, "total": len(keys)}


@router.post("/widget-keys", response_model=WidgetKeyCreateResponse, status_code=status.HTTP_201_CREATED)
async def create_widget_key(
    payload: CreateWidgetKeyRequest,
    merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
):
    """
    Create a new widget key.
    Returns the raw webhook secret once — store it securely; it cannot be retrieved again.
    """
    from src.apps.payment_providers.helpers.credentials import encrypt_credential

    public_key = cart_services.generate_public_key()
    raw_secret: Optional[str] = None
    encrypted_secret: Optional[str] = None

    if payload.webhook_url:
        raw_secret = cart_services.generate_webhook_secret()
        encrypted_secret = encrypt_credential(raw_secret)

    key = cart_crud.create_widget_key(db, merchant.id, payload, public_key, encrypted_secret)
    db.commit()

    response = WidgetKeyCreateResponse(
        id=key.id,
        merchant_id=key.merchant_id,
        display_name=key.display_name,
        public_key=key.public_key,
        allowed_origins=key.allowed_origins,
        webhook_url=key.webhook_url,
        checkout_mode=key.checkout_mode,
        is_active=key.is_active,
        created_at=key.created_at,
        updated_at=key.updated_at,
        revoked_at=key.revoked_at,
        webhook_secret=raw_secret,
    )
    return response


@router.get("/widget-keys/{key_id}", response_model=WidgetKeyResponse)
async def get_widget_key(
    key_id: int,
    merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
):
    """Get widget key details (no secret returned)."""
    key = cart_crud.get_widget_key_by_id(db, key_id, merchant.id)
    if key is None:
        raise NotFoundError(message="Widget key not found.")
    return key


@router.put("/widget-keys/{key_id}", response_model=WidgetKeyResponse)
async def update_widget_key(
    key_id: int,
    payload: UpdateWidgetKeyRequest,
    merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
):
    """Update a widget key's mutable fields."""
    key = cart_crud.get_widget_key_by_id(db, key_id, merchant.id)
    if key is None:
        raise NotFoundError(message="Widget key not found.")
    key = cart_crud.update_widget_key(db, key, payload)
    db.commit()
    return key


@router.delete("/widget-keys/{key_id}", status_code=status.HTTP_204_NO_CONTENT)
async def revoke_widget_key(
    key_id: int,
    merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
):
    """Revoke (soft-delete) a widget key."""
    key = cart_crud.get_widget_key_by_id(db, key_id, merchant.id)
    if key is None:
        raise NotFoundError(message="Widget key not found.")
    cart_crud.revoke_widget_key(db, key)
    db.commit()


@router.post("/widget-keys/{key_id}/rotate-secret", response_model=WidgetKeyCreateResponse)
async def rotate_widget_key_secret(
    key_id: int,
    merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
):
    """
    Rotate the webhook signing secret.
    Returns the new raw secret once — store it securely.
    """
    from src.apps.payment_providers.helpers.credentials import encrypt_credential

    key = cart_crud.get_widget_key_by_id(db, key_id, merchant.id)
    if key is None:
        raise NotFoundError(message="Widget key not found.")

    raw_secret = cart_services.generate_webhook_secret()
    encrypted_secret = encrypt_credential(raw_secret)

    cart_crud.rotate_widget_key_secret(db, key, encrypted_secret)
    db.commit()

    return WidgetKeyCreateResponse(
        id=key.id,
        merchant_id=key.merchant_id,
        display_name=key.display_name,
        public_key=key.public_key,
        allowed_origins=key.allowed_origins,
        webhook_url=key.webhook_url,
        checkout_mode=key.checkout_mode,
        is_active=key.is_active,
        created_at=key.created_at,
        updated_at=key.updated_at,
        revoked_at=key.revoked_at,
        webhook_secret=raw_secret,
    )


# ─── Session endpoints ────────────────────────────────────────────────────────

@router.get("/sessions", response_model=CartSessionListResponse)
async def list_cart_sessions(
    status: Optional[str] = Query(default=None),
    limit: int = Query(default=25, ge=1, le=100),
    offset: int = Query(default=0, ge=0),
    merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
):
    """List cart sessions for the authenticated merchant."""
    sessions, total = cart_crud.list_sessions_for_merchant(
        db, merchant.id, status=status, limit=limit, offset=offset
    )
    items = [
        CartSessionSummary(
            token=s.token,
            status=s.status,
            currency=s.currency,
            subtotal=s.subtotal / 100.0,
            total=s.total / 100.0,
            customer_email=s.customer_email,
            created_at=s.created_at,
            expires_at=s.expires_at,
        )
        for s in sessions
    ]
    return {"items": items, "total": total}


@router.get("/sessions/{token}", response_model=CartSessionDetailResponse)
async def get_cart_session(
    token: str,
    merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
):
    """Get full session detail including line items."""
    session = cart_crud.get_cart_session_with_items(db, token)
    if session is None or session.merchant_id != merchant.id:
        raise NotFoundError(message="Cart session not found.")

    items = [
        {
            "id": item.id,
            "session_id": item.session_id,
            "external_id": item.external_id,
            "name": item.name,
            "description": item.description,
            "quantity": item.quantity,
            "unit_price": item.unit_price / 100.0,
            "image_url": item.image_url,
            "metadata": item.metadata_,
        }
        for item in session.items
    ]

    return {
        "token": session.token,
        "status": session.status,
        "currency": session.currency,
        "checkout_mode": session.checkout_mode,
        "origin": session.origin,
        "return_url": session.return_url,
        "customer_name": session.customer_name,
        "customer_email": session.customer_email,
        "billing_info": session.billing_info,
        "discount_code": session.discount_code,
        "discount_amount": session.discount_amount / 100.0,
        "tip_amount": session.tip_amount / 100.0,
        "tax_amount": session.tax_amount / 100.0,
        "subtotal": session.subtotal / 100.0,
        "total": session.total / 100.0,
        "transaction_id": session.transaction_id,
        "items": items,
        "metadata": session.metadata_,
        "expires_at": session.expires_at,
        "created_at": session.created_at,
        "updated_at": session.updated_at,
    }
