from datetime import datetime, timezone
from enum import Enum
from typing import List, Optional

from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy import select, func
from sqlalchemy.orm import Session
from sqlalchemy.exc import NoResultFound

from app.core.database import get_db
from app.core.auth import get_current_user
from app.models.user import User
from app.models.transaction import Transaction  # siehe Modell unten falls noch nicht vorhanden
from app.schemas.transaction import TransactionOut, TransactionCreate  # siehe Schemas unten

router = APIRouter(prefix="/admin/transactions", tags=["admin-transactions"])

def require_admin(current=Depends(get_current_user)):
  if getattr(current, "role", None) != "admin":
    raise HTTPException(status_code=403, detail="Admin only")
  return current

@router.get("", response_model=List[TransactionOut])
def list_transactions(
    db: Session = Depends(get_db),
    _admin=Depends(require_admin),
    limit: int = Query(200, ge=1, le=500),
    offset: int = Query(0, ge=0),
    order: str = Query("desc", pattern="^(asc|desc)$"),
    status: Optional[str] = Query(None, pattern="^(waiting|approved|rejected)$"),
):
    q = select(Transaction).offset(offset).limit(limit)
    if status:
        q = q.where(Transaction.status == status)
    if order == "desc":
        q = q.order_by(Transaction.created_at.desc())
    else:
        q = q.order_by(Transaction.created_at.asc())
    return db.execute(q).scalars().all()

@router.post("", response_model=TransactionOut, status_code=201)
def create_transaction(
    body: TransactionCreate,
    db: Session = Depends(get_db),
    admin=Depends(require_admin),
):
    tx = Transaction(
        user_id=body.user_id,
        amount_cents=body.amount_cents,
        note=body.note or "",
        status="waiting",
        created_at=datetime.now(timezone.utc),
        created_by_id=admin.id,
        kind="manual",
    )
    db.add(tx)
    db.commit()
    db.refresh(tx)
    return tx

@router.post("/{tx_id}/approve", response_model=TransactionOut)
def approve_transaction(
    tx_id: int,
    db: Session = Depends(get_db),
    admin=Depends(require_admin),
):
    tx = db.get(Transaction, tx_id)
    if not tx:
        raise HTTPException(404, "Transaktion nicht gefunden")
    if tx.status != "waiting":
        raise HTTPException(status_code=409, detail=f"Transaktion bereits {tx.status}")

    # Nutzer sperren, um Doppelbuchungen zu vermeiden
    user = db.execute(
        select(User).where(User.id == tx.user_id).with_for_update()
    ).scalar_one()

    new_balance = (user.balance_cents or 0) + tx.amount_cents
    if new_balance < 0:
        raise HTTPException(400, "Saldo würde negativ – Buchung abgelehnt")

    user.balance_cents = new_balance
    tx.status = "approved"
    tx.processed_at = datetime.now(timezone.utc)
    tx.processed_by_id = admin.id

    db.commit()
    db.refresh(tx)
    return tx

@router.post("/{tx_id}/reject", response_model=TransactionOut)
def reject_transaction(
    tx_id: int,
    db: Session = Depends(get_db),
    admin=Depends(require_admin),
):
    tx = db.get(Transaction, tx_id)
    if not tx:
        raise HTTPException(404, "Transaktion nicht gefunden")
    if tx.status != "waiting":
        raise HTTPException(status_code=409, detail=f"Transaktion bereits {tx.status}")

    tx.status = "rejected"
    tx.processed_at = datetime.now(timezone.utc)
    tx.processed_by_id = admin.id
    db.commit()
    db.refresh(tx)
    return tx
