"""
Routes for reconciliation and exception management.
"""
from fastapi import APIRouter, Depends, HTTPException, Query, Request
from sqlalchemy.orm import Session
from typing import Optional
from datetime import datetime
from ...shared.config.database import get_db
from ...shared.config.logging_config import get_logger
from ...security.middleware.auth import authorize_roles, get_current_user
from ...security.middleware.step_up_auth import authorize_financial_access
from ...auth.models.user import User
from ..services.reconciliation_service import reconciliation_service
from ..models.reconciliation_exception import ExceptionStatus, ExceptionType
from ...shared.utils.response_helpers import success_response

logger = get_logger(__name__)
router = APIRouter(prefix='/financial/reconciliation', tags=['reconciliation'])


@router.post('/run')
async def run_reconciliation(
    start_date: Optional[str] = Query(None),
    end_date: Optional[str] = Query(None),
    current_user: User = Depends(authorize_financial_access('admin', 'accountant')),
    db: Session = Depends(get_db)
):
    """Run reconciliation and detect exceptions."""
    try:
        start = None
        end = None
        
        if start_date:
            start = datetime.fromisoformat(start_date.replace('Z', '+00:00'))
        if end_date:
            end = datetime.fromisoformat(end_date.replace('Z', '+00:00'))
        
        result = reconciliation_service.run_reconciliation(db, start, end)
        db.commit()
        
        return success_response(
            data=result,
            message=f'Reconciliation completed. {result["exceptions_created"]} new exceptions created.'
        )
    except Exception as e:
        db.rollback()
        logger.error(f'Error running reconciliation: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))


@router.get('/exceptions')
async def get_reconciliation_exceptions(
    status: Optional[str] = Query(None),
    exception_type: Optional[str] = Query(None),
    assigned_to: Optional[int] = Query(None),
    severity: Optional[str] = Query(None),
    page: int = Query(1, ge=1),
    limit: int = Query(50, ge=1, le=100),
    current_user: User = Depends(authorize_financial_access('admin', 'accountant')),
    db: Session = Depends(get_db)
):
    """Get reconciliation exceptions with filters."""
    try:
        status_enum = None
        if status:
            try:
                status_enum = ExceptionStatus(status)
            except ValueError:
                raise HTTPException(status_code=400, detail=f'Invalid status: {status}')
        
        type_enum = None
        if exception_type:
            try:
                type_enum = ExceptionType(exception_type)
            except ValueError:
                raise HTTPException(status_code=400, detail=f'Invalid exception_type: {exception_type}')
        
        result = reconciliation_service.get_exceptions(
            db=db,
            status=status_enum,
            exception_type=type_enum,
            assigned_to=assigned_to,
            severity=severity,
            page=page,
            limit=limit
        )
        
        return success_response(data=result)
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f'Error fetching exceptions: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))


@router.post('/exceptions/{exception_id}/assign')
async def assign_exception(
    exception_id: int,
    assign_data: dict,
    current_user: User = Depends(authorize_financial_access('admin', 'accountant')),
    db: Session = Depends(get_db)
):
    """Assign an exception to a user."""
    try:
        assigned_to = assign_data.get('assigned_to')
        if not assigned_to:
            raise HTTPException(status_code=400, detail='assigned_to is required')
        
        exception = reconciliation_service.assign_exception(
            db=db,
            exception_id=exception_id,
            assigned_to=assigned_to
        )
        
        db.commit()
        
        return success_response(
            data={'exception_id': exception.id, 'assigned_to': exception.assigned_to},
            message='Exception assigned successfully'
        )
    except ValueError as e:
        db.rollback()
        raise HTTPException(status_code=404, detail=str(e))
    except Exception as e:
        db.rollback()
        logger.error(f'Error assigning exception: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))


@router.post('/exceptions/{exception_id}/resolve')
async def resolve_exception(
    exception_id: int,
    resolve_data: dict,
    current_user: User = Depends(authorize_financial_access('admin', 'accountant')),
    db: Session = Depends(get_db)
):
    """Resolve an exception."""
    try:
        resolution_notes = resolve_data.get('notes', '')
        if not resolution_notes:
            raise HTTPException(status_code=400, detail='Resolution notes are required')
        
        exception = reconciliation_service.resolve_exception(
            db=db,
            exception_id=exception_id,
            resolved_by=current_user.id,
            resolution_notes=resolution_notes
        )
        
        db.commit()
        
        return success_response(
            data={'exception_id': exception.id, 'status': exception.status.value},
            message='Exception resolved successfully'
        )
    except ValueError as e:
        db.rollback()
        raise HTTPException(status_code=404, detail=str(e))
    except Exception as e:
        db.rollback()
        logger.error(f'Error resolving exception: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))


@router.post('/exceptions/{exception_id}/comment')
async def add_exception_comment(
    exception_id: int,
    comment_data: dict,
    current_user: User = Depends(authorize_financial_access('admin', 'accountant')),
    db: Session = Depends(get_db)
):
    """Add a comment to an exception."""
    try:
        comment = comment_data.get('comment', '')
        if not comment:
            raise HTTPException(status_code=400, detail='Comment is required')
        
        exception = reconciliation_service.add_comment(
            db=db,
            exception_id=exception_id,
            user_id=current_user.id,
            comment=comment
        )
        
        db.commit()
        
        return success_response(
            data={'exception_id': exception.id, 'comments': exception.comments},
            message='Comment added successfully'
        )
    except ValueError as e:
        db.rollback()
        raise HTTPException(status_code=404, detail=str(e))
    except Exception as e:
        db.rollback()
        logger.error(f'Error adding comment: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))


@router.get('/exceptions/stats')
async def get_exception_stats(
    current_user: User = Depends(authorize_financial_access('admin', 'accountant')),
    db: Session = Depends(get_db)
):
    """Get statistics about reconciliation exceptions."""
    try:
        from ..models.reconciliation_exception import ReconciliationException
        from sqlalchemy import func
        
        total = db.query(ReconciliationException).count()
        by_status = db.query(
            ReconciliationException.status,
            func.count(ReconciliationException.id).label('count')
        ).group_by(ReconciliationException.status).all()
        
        by_type = db.query(
            ReconciliationException.exception_type,
            func.count(ReconciliationException.id).label('count')
        ).group_by(ReconciliationException.exception_type).all()
        
        by_severity = db.query(
            ReconciliationException.severity,
            func.count(ReconciliationException.id).label('count')
        ).group_by(ReconciliationException.severity).all()
        
        return success_response(data={
            'total': total,
            'by_status': {status.value: count for status, count in by_status},
            'by_type': {exc_type.value: count for exc_type, count in by_type},
            'by_severity': {severity: count for severity, count in by_severity}
        })
    except Exception as e:
        logger.error(f'Error getting exception stats: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

