from typing import Optional, List, Union from fastapi import APIRouter, HTTPException, Query from loguru import logger from leggend.api.models.common import APIResponse from leggend.api.models.accounts import ( AccountDetails, AccountBalance, Transaction, TransactionSummary, ) from leggend.services.gocardless_service import GoCardlessService from leggend.services.database_service import DatabaseService router = APIRouter() gocardless_service = GoCardlessService() database_service = DatabaseService() @router.get("/accounts", response_model=APIResponse) async def get_all_accounts() -> APIResponse: """Get all connected accounts""" try: requisitions_data = await gocardless_service.get_requisitions() all_accounts = set() for req in requisitions_data.get("results", []): all_accounts.update(req.get("accounts", [])) accounts = [] for account_id in all_accounts: try: account_details = await gocardless_service.get_account_details( account_id ) balances_data = await gocardless_service.get_account_balances( account_id ) # Process balances balances = [] for balance in balances_data.get("balances", []): balance_amount = balance["balanceAmount"] balances.append( AccountBalance( amount=float(balance_amount["amount"]), currency=balance_amount["currency"], balance_type=balance["balanceType"], last_change_date=balance.get("lastChangeDateTime"), ) ) accounts.append( AccountDetails( id=account_details["id"], institution_id=account_details["institution_id"], status=account_details["status"], iban=account_details.get("iban"), name=account_details.get("name"), currency=account_details.get("currency"), created=account_details["created"], last_accessed=account_details.get("last_accessed"), balances=balances, ) ) except Exception as e: logger.error(f"Failed to get details for account {account_id}: {e}") continue return APIResponse( success=True, data=accounts, message=f"Retrieved {len(accounts)} accounts" ) except Exception as e: logger.error(f"Failed to get accounts: {e}") raise HTTPException( status_code=500, detail=f"Failed to get accounts: {str(e)}" ) from e @router.get("/accounts/{account_id}", response_model=APIResponse) async def get_account_details(account_id: str) -> APIResponse: """Get details for a specific account""" try: account_details = await gocardless_service.get_account_details(account_id) balances_data = await gocardless_service.get_account_balances(account_id) # Process balances balances = [] for balance in balances_data.get("balances", []): balance_amount = balance["balanceAmount"] balances.append( AccountBalance( amount=float(balance_amount["amount"]), currency=balance_amount["currency"], balance_type=balance["balanceType"], last_change_date=balance.get("lastChangeDateTime"), ) ) account = AccountDetails( id=account_details["id"], institution_id=account_details["institution_id"], status=account_details["status"], iban=account_details.get("iban"), name=account_details.get("name"), currency=account_details.get("currency"), created=account_details["created"], last_accessed=account_details.get("last_accessed"), balances=balances, ) return APIResponse( success=True, data=account, message=f"Account details retrieved for {account_id}", ) except Exception as e: logger.error(f"Failed to get account details for {account_id}: {e}") raise HTTPException( status_code=404, detail=f"Account not found: {str(e)}" ) from e @router.get("/accounts/{account_id}/balances", response_model=APIResponse) async def get_account_balances(account_id: str) -> APIResponse: """Get balances for a specific account from database""" try: # Get balances from database instead of GoCardless API db_balances = await database_service.get_balances_from_db(account_id=account_id) balances = [] for balance in db_balances: balances.append( AccountBalance( amount=balance["amount"], currency=balance["currency"], balance_type=balance["type"], last_change_date=balance.get("timestamp"), ) ) return APIResponse( success=True, data=balances, message=f"Retrieved {len(balances)} balances for account {account_id}", ) except Exception as e: logger.error( f"Failed to get balances from database for account {account_id}: {e}" ) raise HTTPException( status_code=404, detail=f"Failed to get balances: {str(e)}" ) from e @router.get("/accounts/{account_id}/transactions", response_model=APIResponse) async def get_account_transactions( account_id: str, limit: Optional[int] = Query(default=100, le=500), offset: Optional[int] = Query(default=0, ge=0), summary_only: bool = Query( default=False, description="Return transaction summaries only" ), ) -> APIResponse: """Get transactions for a specific account from database""" try: # Get transactions from database instead of GoCardless API db_transactions = await database_service.get_transactions_from_db( account_id=account_id, limit=limit, offset=offset, ) # Get total count for pagination info total_transactions = await database_service.get_transaction_count_from_db( account_id=account_id, ) data: Union[List[TransactionSummary], List[Transaction]] if summary_only: # Return simplified transaction summaries data = [ TransactionSummary( internal_transaction_id=txn["internalTransactionId"], date=txn["transactionDate"], description=txn["description"], amount=txn["transactionValue"], currency=txn["transactionCurrency"], status=txn["transactionStatus"], account_id=txn["accountId"], ) for txn in db_transactions ] else: # Return full transaction details data = [ Transaction( internal_transaction_id=txn["internalTransactionId"], institution_id=txn["institutionId"], iban=txn["iban"], account_id=txn["accountId"], transaction_date=txn["transactionDate"], description=txn["description"], transaction_value=txn["transactionValue"], transaction_currency=txn["transactionCurrency"], transaction_status=txn["transactionStatus"], raw_transaction=txn["rawTransaction"], ) for txn in db_transactions ] actual_offset = offset or 0 return APIResponse( success=True, data=data, message=f"Retrieved {len(data)} transactions (showing {actual_offset + 1}-{actual_offset + len(data)} of {total_transactions})", ) except Exception as e: logger.error( f"Failed to get transactions from database for account {account_id}: {e}" ) raise HTTPException( status_code=404, detail=f"Failed to get transactions: {str(e)}" ) from e