# app/api/topups.py
from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy.orm import Session
from typing import List, Optional, Literal
from pydantic import BaseModel

from app.core.database import get_db
from app.core.auth import get_current_user, requires_role
from app.models.user import User
from app.models.topup import Topup, TopupStatus as DBTopupStatus
from app.schemas.topup import TopupOut, TopupCreate  # Pydantic v2 Schemas

# Optionales Audit-Log – nur nutzen, wenn vorhanden
try:
    from app.models.audit_log import AuditLog, AuditAction
    HAS_AUDIT = True
except Exception:
    AuditLog = None
    AuditAction = None
    HAS_AUDIT = False

router = APIRouter(prefix="/topups", tags=["topups"])


# ---------------------------
# CREATE (User oder Admin)
# ---------------------------
@router.post("/", response_model=TopupOut, status_code=status.HTTP_201_CREATED)
def create_topup(
    topup: TopupCreate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """
    Legt ein Topup an. amount_cents ist Pflicht. user_id ist optional; wenn nicht gesetzt,
    wird der aktuelle User verwendet.
    """
    payload = topup.model_dump()  # Pydantic v2

    # user_id für User-Flow ergänzen
    user_id = payload.get("user_id") or current_user.id
    amount_cents = int(payload.get("amount_cents") or 0)
    if amount_cents <= 0:
        raise HTTPException(status_code=400, detail="amount_cents must be > 0")

    db_topup = Topup(
        user_id=user_id,
        amount_cents=amount_cents,
        paypal_email=payload.get("paypal_email"),
        note=payload.get("note"),
        # status default: pending (siehe Model)
    )

    db.add(db_topup)
    db.commit()
    db.refresh(db_topup)

    if HAS_AUDIT:
        db.add(
            AuditLog(
                user_id=db_topup.user_id,
                action=getattr(AuditAction, "topup_create", "topup_create"),
                amount_cents=db_topup.amount_cents,
                info=f"created by {current_user.id}",
            )
        )
        db.commit()

    return db_topup


# ---------------------------
# LIST (Admin/Manager, gefiltert)
# ---------------------------
@router.get("/", response_model=List[TopupOut], dependencies=[Depends(requires_role("manager", "admin"))])
def list_topups(
    user_id: Optional[int] = Query(default=None),
    status_filter: Optional[str] = Query(default=None, description="pending|confirmed|rejected"),
    limit: int = Query(default=100, ge=1, le=1000),
    offset: int = Query(default=0, ge=0),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    q = db.query(Topup)
    if user_id is not None:
        q = q.filter(Topup.user_id == user_id)
    if status_filter:
        try:
            enum_val = DBTopupStatus(status_filter)
        except ValueError:
            raise HTTPException(status_code=400, detail="invalid status_filter")
        q = q.filter(Topup.status == enum_val)
    q = q.order_by(Topup.id.desc()).limit(limit).offset(offset)
    return q.all()


# ---------------------------
# LIST OWN (alle eingeloggten)
# ---------------------------
@router.get("/me", response_model=List[TopupOut])
def list_my_topups(
    limit: int = Query(default=100, ge=1, le=1000),
    offset: int = Query(default=0, ge=0),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    q = (
        db.query(Topup)
        .filter(Topup.user_id == current_user.id)
        .order_by(Topup.id.desc())
        .limit(limit)
        .offset(offset)
    )
    return q.all()


# ---------------------------
# STATUS ändern (Admin/Manager)
# ---------------------------
class TopupStatusIn(BaseModel):
    status: Literal["confirmed", "rejected"]


@router.patch("/{topup_id}/status", dependencies=[Depends(requires_role("manager", "admin"))])
def patch_topup_status(
    topup_id: int,
    payload: TopupStatusIn,
    db: Session = Depends(get_db),
    admin: User = Depends(get_current_user),
):
    t = db.query(Topup).filter(Topup.id == topup_id).first()
    if not t:
        raise HTTPException(status_code=404, detail="Topup not found")

    # robustes Enum-Handling
    old_enum = t.status if isinstance(t.status, DBTopupStatus) else DBTopupStatus(str(t.status))
    try:
        new_enum = DBTopupStatus(payload.status)
    except ValueError:
        raise HTTPException(status_code=400, detail="invalid status")

    if old_enum == new_enum:
        return {"status": "ok", "topup_id": t.id, "new_status": old_enum.value}

    # Status setzen
    t.status = new_enum

    # Balance nur bei Übergang zu 'confirmed' buchen (idempotent)
    if new_enum == DBTopupStatus.confirmed and old_enum != DBTopupStatus.confirmed:
        u = db.query(User).filter(User.id == t.user_id).first()
        if not u:
            raise HTTPException(status_code=404, detail="User for topup not found")

        before = int(u.balance_cents or 0)
        u.balance_cents = before + int(t.amount_cents or 0)

        if HAS_AUDIT:
            db.add(
                AuditLog(
                    user_id=u.id,
                    action=getattr(AuditAction, "topup_confirmed", "topup_confirmed"),
                    amount_cents=int(t.amount_cents or 0),
                    old_balance_cents=before,
                    new_balance_cents=u.balance_cents,
                    info=f"topup:{t.id} confirmed by {admin.id}",
                )
            )

    # (Kein automatisches Reversal bei Wechsel zu rejected)

    db.commit()
    db.refresh(t)
    return {"status": "ok", "topup_id": t.id, "new_status": t.status.value}


# ---------------------------
# DELETE (Admin/Manager)
# ---------------------------
@router.delete("/{topup_id}", status_code=status.HTTP_204_NO_CONTENT, dependencies=[Depends(requires_role("manager", "admin"))])
def delete_topup(
    topup_id: int,
    db: Session = Depends(get_db),
    admin: User = Depends(get_current_user),
):
    t = db.query(Topup).filter(Topup.id == topup_id).first()
    if not t:
        raise HTTPException(status_code=404, detail="Topup not found")

    db.delete(t)
    db.commit()

    if HAS_AUDIT:
        db.add(
            AuditLog(
                user_id=t.user_id,
                action=getattr(AuditAction, "topup_delete", "topup_delete"),
                amount_cents=int(t.amount_cents or 0),
                info=f"topup:{t.id} deleted by {admin.id}",
            )
        )
        db.commit()

    return None
