# services/auth/app/api/password_reset.py
"""
Password reset API endpoints
Handles forgot password and password reset functionality
"""

import logging
from datetime import datetime, timedelta, timezone
from typing import Dict, Any
from fastapi import APIRouter, Depends, HTTPException, status, BackgroundTasks
from app.services.auth_service import auth_service, AuthService
from app.schemas.auth import PasswordReset, PasswordResetConfirm
from app.core.security import SecurityManager
from app.core.config import settings
from app.repositories.password_reset_repository import PasswordResetTokenRepository
from app.repositories.user_repository import UserRepository
from app.models.users import User
from shared.clients.notification_client import NotificationServiceClient
import structlog

# Configure logging
logger = structlog.get_logger()

# Create router
router = APIRouter(prefix="/api/v1/auth", tags=["password-reset"])


async def get_auth_service() -> AuthService:
    """Dependency injection for auth service"""
    return auth_service


def generate_reset_token() -> str:
    """Generate a secure password reset token"""
    import secrets
    return secrets.token_urlsafe(32)


async def send_password_reset_email(email: str, reset_token: str, user_full_name: str):
    """Send password reset email in background using notification service"""
    try:
        # Construct reset link (this should match your frontend URL)
        # Use FRONTEND_URL from settings if available, otherwise fall back to gateway URL
        frontend_url = getattr(settings, 'FRONTEND_URL', settings.GATEWAY_URL)
        reset_link = f"{frontend_url}/reset-password?token={reset_token}"

        # Create HTML content for the password reset email in Spanish
        html_content = f"""
        <!DOCTYPE html>
        <html lang="es">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Restablecer Contraseña</title>
            <style>
                body {{
                    font-family: Arial, sans-serif;
                    line-height: 1.6;
                    color: #333;
                    max-width: 600px;
                    margin: 0 auto;
                    padding: 20px;
                    background-color: #f9f9f9;
                }}
                .header {{
                    text-align: center;
                    margin-bottom: 30px;
                    background: linear-gradient(135deg, #4F46E5 0%, #7C3AED 100%);
                    color: white;
                    padding: 20px;
                    border-radius: 8px;
                }}
                .content {{
                    background: white;
                    padding: 30px;
                    border-radius: 8px;
                    box-shadow: 0 2px 10px rgba(0,0,0,0.1);
                }}
                .button {{
                    display: inline-block;
                    padding: 12px 30px;
                    background-color: #4F46E5;
                    color: white;
                    text-decoration: none;
                    border-radius: 5px;
                    margin: 20px 0;
                    font-weight: bold;
                }}
                .footer {{
                    margin-top: 40px;
                    text-align: center;
                    font-size: 0.9em;
                    color: #666;
                    padding-top: 20px;
                    border-top: 1px solid #eee;
                }}
            </style>
        </head>
        <body>
            <div class="header">
                <h1>Restablecer Contraseña</h1>
            </div>

            <div class="content">
                <p>Hola {user_full_name},</p>

                <p>Recibimos una solicitud para restablecer tu contraseña. Haz clic en el botón de abajo para crear una nueva contraseña:</p>

                <p style="text-align: center; margin: 30px 0;">
                    <a href="{reset_link}" class="button">Restablecer Contraseña</a>
                </p>

                <p>Si no solicitaste un restablecimiento de contraseña, puedes ignorar este correo electrónico de forma segura.</p>

                <p>Este enlace expirará en 1 hora por razones de seguridad.</p>
            </div>

            <div class="footer">
                <p>Este es un mensaje automático de BakeWise. Por favor, no respondas a este correo electrónico.</p>
            </div>
        </body>
        </html>
        """

        # Create text content as fallback
        text_content = f"""
        Hola {user_full_name},

        Recibimos una solicitud para restablecer tu contraseña. Haz clic en el siguiente enlace para crear una nueva contraseña:

        {reset_link}

        Si no solicitaste un restablecimiento de contraseña, puedes ignorar este correo electrónico de forma segura.

        Este enlace expirará en 1 hora por razones de seguridad.

        Este es un mensaje automático de BakeWise. Por favor, no respondas a este correo electrónico.
        """

        # Send email using the notification service
        notification_client = NotificationServiceClient(settings)

        # Send the notification using the send_email method
        await notification_client.send_email(
            tenant_id="system",  # Using system tenant for password resets
            to_email=email,
            subject="Restablecer Contraseña",
            message=text_content,
            html_content=html_content,
            priority="high"
        )

        logger.info(f"Password reset email sent successfully to {email}")
    except Exception as e:
        logger.error(f"Failed to send password reset email to {email}: {str(e)}")


@router.post("/password/reset-request",
            summary="Request password reset",
            description="Send a password reset link to the user's email")
async def request_password_reset(
    reset_request: PasswordReset,
    background_tasks: BackgroundTasks,
    auth_service: AuthService = Depends(get_auth_service)
) -> Dict[str, Any]:
    """
    Request a password reset
    
    This endpoint:
    1. Finds the user by email
    2. Generates a password reset token
    3. Stores the token in the database
    4. Sends a password reset email to the user
    """
    try:
        logger.info(f"Password reset request for email: {reset_request.email}")

        # Find user by email
        async with auth_service.database_manager.get_session() as session:
            user_repo = UserRepository(User, session)
            user = await user_repo.get_by_field("email", reset_request.email)

            if not user:
                # Don't reveal if email exists to prevent enumeration attacks
                logger.info(f"Password reset request for non-existent email: {reset_request.email}")
                return {"message": "If an account with this email exists, a reset link has been sent."}

            # Generate a secure reset token
            reset_token = generate_reset_token()
            
            # Set token expiration (e.g., 1 hour)
            expires_at = datetime.now(timezone.utc) + timedelta(hours=1)
            
            # Store the reset token in the database
            token_repo = PasswordResetTokenRepository(session)
            
            # Clean up any existing unused tokens for this user
            await token_repo.cleanup_expired_tokens()
            
            # Create new reset token
            await token_repo.create_token(
                user_id=str(user.id),
                token=reset_token,
                expires_at=expires_at
            )
            
            # Commit the transaction
            await session.commit()

            # Send password reset email in background
            background_tasks.add_task(
                send_password_reset_email,
                user.email,
                reset_token,
                user.full_name
            )

            logger.info(f"Password reset token created for user: {user.email}")

            return {"message": "If an account with this email exists, a reset link has been sent."}

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Password reset request failed: {str(e)}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Password reset request failed"
        )


@router.post("/password/reset",
            summary="Reset password with token",
            description="Reset user password using a valid reset token")
async def reset_password(
    reset_confirm: PasswordResetConfirm,
    auth_service: AuthService = Depends(get_auth_service)
) -> Dict[str, Any]:
    """
    Reset password using a valid reset token
    
    This endpoint:
    1. Validates the reset token
    2. Checks if the token is valid and not expired
    3. Updates the user's password
    4. Marks the token as used
    """
    try:
        logger.info(f"Password reset attempt with token: {reset_confirm.token[:10]}...")

        # Validate password strength
        if not SecurityManager.validate_password(reset_confirm.new_password):
            errors = SecurityManager.get_password_validation_errors(reset_confirm.new_password)
            logger.warning(f"Password validation failed: {errors}")
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Password does not meet requirements: {'; '.join(errors)}"
            )

        # Find the reset token in the database
        async with auth_service.database_manager.get_session() as session:
            token_repo = PasswordResetTokenRepository(session)
            reset_token_obj = await token_repo.get_token_by_value(reset_confirm.token)

            if not reset_token_obj:
                logger.warning(f"Invalid or expired password reset token: {reset_confirm.token[:10]}...")
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="Invalid or expired reset token"
                )

            # Get the user associated with this token
            user_repo = UserRepository(User, session)
            user = await user_repo.get_by_id(str(reset_token_obj.user_id))

            if not user:
                logger.error(f"User not found for reset token: {reset_confirm.token[:10]}...")
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="Invalid reset token"
                )

            # Hash the new password
            hashed_password = SecurityManager.hash_password(reset_confirm.new_password)

            # Update user's password
            await user_repo.update(str(user.id), {
                "hashed_password": hashed_password
            })

            # Mark the reset token as used
            await token_repo.mark_token_as_used(str(reset_token_obj.id))
            
            # Commit the transactions
            await session.commit()

            logger.info(f"Password successfully reset for user: {user.email}")

            return {"message": "Password has been reset successfully"}

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Password reset failed: {str(e)}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Password reset failed"
        )