from sqlalchemy.orm import Session
from fastapi import HTTPException, status
from typing import Optional, List
from . import repository
from .schema import TransactionCreate, TransactionUpdate, TransactionResponse
from user_management import repository as user_repo
from order_management import repository as order_repo


def _get_or_raise(db: Session, entity_id: str) -> repository.Transaction:
    entity = repository.get_by_id(db, entity_id)
    if not entity:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Transaction with id {entity_id} not found"
        )
    return entity


def create_transaction(db: Session, data: TransactionCreate) -> TransactionResponse:
    user = user_repo.get_by_id(db, data.user_id)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"User with id {data.user_id} not found"
        )
    
    if data.order_id:
        order = order_repo.get_by_id(db, data.order_id)
        if not order:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Order with id {data.order_id} not found"
            )
    
    try:
        transaction = repository.create(db, data.model_dump())
        db.commit()
        db.refresh(transaction)
        return TransactionResponse.model_validate(transaction)
    except Exception:
        db.rollback()
        raise


def get_transaction(db: Session, entity_id: str) -> TransactionResponse:
    transaction = _get_or_raise(db, entity_id)
    return TransactionResponse.model_validate(transaction)


def list_transactions(
    db: Session,
    limit: int,
    offset: int,
    user_id: Optional[str] = None,
    order_id: Optional[str] = None,
    transaction_type: Optional[str] = None,
    status: Optional[str] = None,
) -> List[TransactionResponse]:
    transactions = repository.list_all(
        db,
        limit=limit,
        offset=offset,
        user_id=user_id,
        order_id=order_id,
        transaction_type=transaction_type,
        status=status,
    )
    return [TransactionResponse.model_validate(t) for t in transactions]


def update_transaction(db: Session, entity_id: str, data: TransactionUpdate) -> TransactionResponse:
    _get_or_raise(db, entity_id)
    
    update_data = data.model_dump(exclude_unset=True)
    
    if "user_id" in update_data:
        user = user_repo.get_by_id(db, update_data["user_id"])
        if not user:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"User with id {update_data['user_id']} not found"
            )
    
    if "order_id" in update_data and update_data["order_id"] is not None:
        order = order_repo.get_by_id(db, update_data["order_id"])
        if not order:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Order with id {update_data['order_id']} not found"
            )
    
    try:
        transaction = repository.update(db, entity_id, update_data)
        db.commit()
        db.refresh(transaction)
        return TransactionResponse.model_validate(transaction)
    except Exception:
        db.rollback()
        raise


def delete_transaction(db: Session, entity_id: str) -> dict:
    _get_or_raise(db, entity_id)
    
    try:
        repository.delete(db, entity_id)
        db.commit()
        return {"message": "Transaction deleted successfully"}
    except Exception:
        db.rollback()
        raise