"""
Service for creating and managing financial audit trail records.
"""
from sqlalchemy.orm import Session
from sqlalchemy.exc import ProgrammingError, OperationalError
from typing import Optional, Dict, Any
from datetime import datetime
from ..models.financial_audit_trail import FinancialAuditTrail, FinancialActionType
from ...auth.models.user import User
from ...shared.config.logging_config import get_logger

logger = get_logger(__name__)


class FinancialAuditService:
    """Service for financial audit trail operations."""
    
    @staticmethod
    def log_financial_action(
        db: Session,
        action_type: FinancialActionType,
        performed_by: int,
        action_description: str,
        payment_id: Optional[int] = None,
        invoice_id: Optional[int] = None,
        booking_id: Optional[int] = None,
        amount: Optional[float] = None,
        previous_amount: Optional[float] = None,
        currency: Optional[str] = None,
        metadata: Optional[Dict[str, Any]] = None,
        notes: Optional[str] = None
    ) -> FinancialAuditTrail:
        """Log a financial action to the audit trail."""
        try:
            # Get user email for audit trail
            user = db.query(User).filter(User.id == performed_by).first()
            user_email = user.email if user else None
            
            audit_record = FinancialAuditTrail(
                action_type=action_type,
                action_description=action_description,
                payment_id=payment_id,
                invoice_id=invoice_id,
                booking_id=booking_id,
                amount=amount,
                previous_amount=previous_amount,
                currency=currency or 'USD',
                performed_by=performed_by,
                performed_by_email=user_email,
                audit_metadata=metadata or {},
                notes=notes,
                created_at=datetime.utcnow()
            )
            
            # SECURITY: Ensure append-only behavior - prevent any updates to existing records
            # This is enforced at the database level, but we also check here
            if hasattr(audit_record, 'id') and audit_record.id:
                # If somehow an ID exists, this shouldn't happen for new records
                logger.warning(f"Attempted to create audit record with existing ID: {audit_record.id}")
            
            db.add(audit_record)
            db.flush()  # Flush to get ID without committing
            
            logger.info(f"Financial audit trail created: {action_type.value} by user {performed_by}")
            return audit_record
        except (ProgrammingError, OperationalError) as e:
            error_msg = str(e)
            if 'doesn\'t exist' in error_msg or 'Table' in error_msg:
                logger.warning(f"Financial audit trail table not found, skipping audit logging: {error_msg}")
                # Don't fail the main operation if audit table doesn't exist
                return None
            logger.error(f"Database error creating financial audit trail: {str(e)}", exc_info=True)
            # Don't fail the main operation if audit logging fails
            raise
        except Exception as e:
            logger.error(f"Error creating financial audit trail: {str(e)}", exc_info=True)
            # Don't fail the main operation if audit logging fails
            raise
    
    @staticmethod
    def get_audit_trail(
        db: Session,
        payment_id: Optional[int] = None,
        invoice_id: Optional[int] = None,
        booking_id: Optional[int] = None,
        action_type: Optional[FinancialActionType] = None,
        user_id: Optional[int] = None,
        start_date: Optional[datetime] = None,
        end_date: Optional[datetime] = None,
        limit: int = 100,
        offset: int = 0
    ) -> list[FinancialAuditTrail]:
        """Get audit trail records with filters."""
        query = db.query(FinancialAuditTrail)
        
        if payment_id:
            query = query.filter(FinancialAuditTrail.payment_id == payment_id)
        if invoice_id:
            query = query.filter(FinancialAuditTrail.invoice_id == invoice_id)
        if booking_id:
            query = query.filter(FinancialAuditTrail.booking_id == booking_id)
        if action_type:
            query = query.filter(FinancialAuditTrail.action_type == action_type)
        if user_id:
            query = query.filter(FinancialAuditTrail.performed_by == user_id)
        if start_date:
            query = query.filter(FinancialAuditTrail.created_at >= start_date)
        if end_date:
            query = query.filter(FinancialAuditTrail.created_at <= end_date)
        
        query = query.order_by(FinancialAuditTrail.created_at.desc())
        query = query.limit(limit).offset(offset)
        
        try:
            return query.all()
        except (ProgrammingError, OperationalError) as e:
            error_msg = str(e)
            if 'doesn\'t exist' in error_msg or 'Table' in error_msg:
                logger.warning(f"Financial audit trail table not found: {error_msg}")
                return []
            raise


financial_audit_service = FinancialAuditService()

