"""
Authentication API Blueprint

This module provides API endpoints for user authentication and management:
- User registration
- User login/logout
- Email verification
- Password reset

All endpoints follow the standard API response format defined in app.utils.response.
"""

import re
from flask import Blueprint, request, make_response, render_template, redirect, url_for, flash
from appwrite.exception import AppwriteException

from app.services.appwrite_service import AppwriteService
from app.utils.response import (
    success_response,
    created_response,
    error_response,
    unauthorized_response,
    validation_error_response
)
from app.utils.auth import require_auth, get_current_user, extract_session_token
from app.utils.logging import get_logger
from app.config import get_config


# Initialize logger
logger = get_logger(__file__)

# Create blueprint
auth_bp = Blueprint('auth', __name__)


# ===== VALIDATION FUNCTIONS =====

def validate_email(email: str) -> tuple[bool, str]:
    """
    Validate email address format.

    Args:
        email: Email address to validate

    Returns:
        Tuple of (is_valid, error_message)
    """
    if not email:
        return False, "Email is required"

    config = get_config()
    max_length = config.auth.email_max_length

    if len(email) > max_length:
        return False, f"Email must be no more than {max_length} characters"

    # Email regex pattern
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    if not re.match(pattern, email):
        return False, "Invalid email format"

    return True, ""


def validate_password(password: str) -> tuple[bool, str]:
    """
    Validate password strength.

    Args:
        password: Password to validate

    Returns:
        Tuple of (is_valid, error_message)
    """
    if not password:
        return False, "Password is required"

    config = get_config()

    min_length = config.auth.password_min_length
    if len(password) < min_length:
        return False, f"Password must be at least {min_length} characters long"

    if len(password) > 128:
        return False, "Password must be no more than 128 characters"

    errors = []

    if config.auth.password_require_uppercase and not re.search(r'[A-Z]', password):
        errors.append("at least one uppercase letter")

    if config.auth.password_require_lowercase and not re.search(r'[a-z]', password):
        errors.append("at least one lowercase letter")

    if config.auth.password_require_number and not re.search(r'[0-9]', password):
        errors.append("at least one number")

    if config.auth.password_require_special and not re.search(r'[!@#$%^&*()_+\-=\[\]{}|;:,.<>?]', password):
        errors.append("at least one special character")

    if errors:
        return False, f"Password must contain {', '.join(errors)}"

    return True, ""


def validate_name(name: str) -> tuple[bool, str]:
    """
    Validate user name.

    Args:
        name: Name to validate

    Returns:
        Tuple of (is_valid, error_message)
    """
    if not name:
        return False, "Name is required"

    config = get_config()

    min_length = config.auth.name_min_length
    max_length = config.auth.name_max_length

    if len(name) < min_length:
        return False, f"Name must be at least {min_length} characters"

    if len(name) > max_length:
        return False, f"Name must be no more than {max_length} characters"

    # Allow letters, spaces, hyphens, apostrophes
    if not re.match(r"^[a-zA-Z\s\-']+$", name):
        return False, "Name can only contain letters, spaces, hyphens, and apostrophes"

    return True, ""


# ===== API ENDPOINTS =====

@auth_bp.route('/api/v1/auth/register', methods=['POST'])
def api_register():
    """
    Register a new user account.

    Request Body:
        {
            "email": "user@example.com",
            "password": "SecurePass123!",
            "name": "Player Name"
        }

    Returns:
        201: User created successfully
        400: Validation error or email already exists
        500: Internal server error
    """
    try:
        # Get request data
        data = request.get_json()

        if not data:
            return validation_error_response({"error": "Request body is required"})

        email = data.get('email', '').strip().lower()
        password = data.get('password', '')
        name = data.get('name', '').strip()

        # Validate inputs
        validation_errors = {}

        email_valid, email_error = validate_email(email)
        if not email_valid:
            validation_errors['email'] = email_error

        password_valid, password_error = validate_password(password)
        if not password_valid:
            validation_errors['password'] = password_error

        name_valid, name_error = validate_name(name)
        if not name_valid:
            validation_errors['name'] = name_error

        if validation_errors:
            return validation_error_response(validation_errors)

        # Register user
        appwrite = AppwriteService()
        user_data = appwrite.register_user(email=email, password=password, name=name)

        logger.info("User registered successfully", user_id=user_data.id, email=email)

        return created_response(
            result={
                "user": user_data.to_dict(),
                "message": "Registration successful. Please check your email to verify your account."
            }
        )

    except AppwriteException as e:
        logger.error("Registration failed", error=str(e), code=e.code)

        # Check for specific error codes
        if e.code == 409:  # Conflict - user already exists
            return validation_error_response({"email": "An account with this email already exists"})

        return error_response(message="Registration failed. Please try again.", code="REGISTRATION_ERROR")

    except Exception as e:
        logger.error("Unexpected error during registration", error=str(e))
        return error_response(message="An unexpected error occurred", code="INTERNAL_ERROR")


@auth_bp.route('/api/v1/auth/login', methods=['POST'])
def api_login():
    """
    Authenticate a user and create a session.

    Request Body:
        {
            "email": "user@example.com",
            "password": "SecurePass123!",
            "remember_me": false
        }

    Returns:
        200: Login successful, session cookie set
        401: Invalid credentials
        400: Validation error
        500: Internal server error
    """
    try:
        # Get request data
        data = request.get_json()

        if not data:
            return validation_error_response({"error": "Request body is required"})

        email = data.get('email', '').strip().lower()
        password = data.get('password', '')
        remember_me = data.get('remember_me', False)

        # Validate inputs
        if not email:
            return validation_error_response({"email": "Email is required"})

        if not password:
            return validation_error_response({"password": "Password is required"})

        # Authenticate user
        appwrite = AppwriteService()
        session_data, user_data = appwrite.login_user(email=email, password=password)

        logger.info("User logged in successfully", user_id=user_data.id, email=email)

        # Set session cookie
        config = get_config()
        duration = config.auth.duration_remember_me if remember_me else config.auth.duration_normal

        response = make_response(success_response(
            result={
                "user": user_data.to_dict(),
                "message": "Login successful"
            }
        ))

        response.set_cookie(
            key=config.auth.cookie_name,
            value=session_data.session_id,
            max_age=duration,
            httponly=config.auth.http_only,
            secure=config.auth.secure,
            samesite=config.auth.same_site,
            path=config.auth.path
        )

        return response

    except AppwriteException as e:
        logger.warning("Login failed", email=email if 'email' in locals() else 'unknown', error=str(e), code=e.code)

        # Generic error message for security (don't reveal if email exists)
        return unauthorized_response(message="Invalid email or password")

    except Exception as e:
        logger.error("Unexpected error during login", error=str(e))
        return error_response(message="An unexpected error occurred", code="INTERNAL_ERROR")


@auth_bp.route('/api/v1/auth/logout', methods=['POST'])
@require_auth
def api_logout():
    """
    Log out the current user by deleting their session.

    Returns:
        200: Logout successful, session cookie cleared
        401: Not authenticated
        500: Internal server error
    """
    try:
        # Get session token
        token = extract_session_token()

        if not token:
            return unauthorized_response(message="No active session")

        # Logout user
        appwrite = AppwriteService()
        appwrite.logout_user(session_id=token)

        user = get_current_user()
        logger.info("User logged out successfully", user_id=user.id if user else 'unknown')

        # Clear session cookie
        config = get_config()

        response = make_response(success_response(
            result={"message": "Logout successful"}
        ))

        response.set_cookie(
            key=config.auth.cookie_name,
            value='',
            max_age=0,
            httponly=config.auth.http_only,
            secure=config.auth.secure,
            samesite=config.auth.same_site,
            path=config.auth.path
        )

        return response

    except AppwriteException as e:
        logger.error("Logout failed", error=str(e), code=e.code)
        return error_response(message="Logout failed", code="LOGOUT_ERROR")

    except Exception as e:
        logger.error("Unexpected error during logout", error=str(e))
        return error_response(message="An unexpected error occurred", code="INTERNAL_ERROR")


@auth_bp.route('/api/v1/auth/verify-email', methods=['GET'])
def api_verify_email():
    """
    Verify a user's email address.

    Query Parameters:
        userId: User ID from verification link
        secret: Verification secret from verification link

    Returns:
        Redirects to login page with success/error message
    """
    try:
        user_id = request.args.get('userId')
        secret = request.args.get('secret')

        if not user_id or not secret:
            flash("Invalid verification link", "error")
            return redirect(url_for('auth.login_page'))

        # Verify email
        appwrite = AppwriteService()
        appwrite.verify_email(user_id=user_id, secret=secret)

        logger.info("Email verified successfully", user_id=user_id)

        flash("Email verified successfully! You can now log in.", "success")
        return redirect(url_for('auth.login_page'))

    except AppwriteException as e:
        logger.error("Email verification failed", error=str(e), code=e.code)
        flash("Email verification failed. The link may be invalid or expired.", "error")
        return redirect(url_for('auth.login_page'))

    except Exception as e:
        logger.error("Unexpected error during email verification", error=str(e))
        flash("An unexpected error occurred", "error")
        return redirect(url_for('auth.login_page'))


@auth_bp.route('/api/v1/auth/forgot-password', methods=['POST'])
def api_forgot_password():
    """
    Request a password reset email.

    Request Body:
        {
            "email": "user@example.com"
        }

    Returns:
        200: Always returns success (for security, don't reveal if email exists)
        400: Validation error
        500: Internal server error
    """
    try:
        # Get request data
        data = request.get_json()

        if not data:
            return validation_error_response({"error": "Request body is required"})

        email = data.get('email', '').strip().lower()

        # Validate email
        email_valid, email_error = validate_email(email)
        if not email_valid:
            return validation_error_response({"email": email_error})

        # Request password reset
        appwrite = AppwriteService()
        appwrite.request_password_reset(email=email)

        logger.info("Password reset requested", email=email)

        # Always return success for security
        return success_response(
            result={
                "message": "If an account exists with this email, you will receive a password reset link shortly."
            }
        )

    except Exception as e:
        logger.error("Unexpected error during password reset request", error=str(e))
        # Still return success for security
        return success_response(
            result={
                "message": "If an account exists with this email, you will receive a password reset link shortly."
            }
        )


@auth_bp.route('/api/v1/auth/reset-password', methods=['POST'])
def api_reset_password():
    """
    Confirm password reset and update password.

    Request Body:
        {
            "user_id": "user_id_from_link",
            "secret": "secret_from_link",
            "password": "NewSecurePass123!"
        }

    Returns:
        200: Password reset successful
        400: Validation error or invalid/expired link
        500: Internal server error
    """
    try:
        # Get request data
        data = request.get_json()

        if not data:
            return validation_error_response({"error": "Request body is required"})

        user_id = data.get('user_id', '').strip()
        secret = data.get('secret', '').strip()
        password = data.get('password', '')

        # Validate inputs
        validation_errors = {}

        if not user_id:
            validation_errors['user_id'] = "User ID is required"

        if not secret:
            validation_errors['secret'] = "Reset secret is required"

        password_valid, password_error = validate_password(password)
        if not password_valid:
            validation_errors['password'] = password_error

        if validation_errors:
            return validation_error_response(validation_errors)

        # Confirm password reset
        appwrite = AppwriteService()
        appwrite.confirm_password_reset(user_id=user_id, secret=secret, password=password)

        logger.info("Password reset successfully", user_id=user_id)

        return success_response(
            result={
                "message": "Password reset successful. You can now log in with your new password."
            }
        )

    except AppwriteException as e:
        logger.error("Password reset failed", error=str(e), code=e.code)
        return error_response(
            message="Password reset failed. The link may be invalid or expired.",
            code="PASSWORD_RESET_ERROR"
        )

    except Exception as e:
        logger.error("Unexpected error during password reset", error=str(e))
        return error_response(message="An unexpected error occurred", code="INTERNAL_ERROR")


# ===== TEMPLATE ROUTES (for rendering HTML pages) =====

@auth_bp.route('/login', methods=['GET'])
def login_page():
    """Render the login page."""
    return render_template('auth/login.html')


@auth_bp.route('/register', methods=['GET'])
def register_page():
    """Render the registration page."""
    return render_template('auth/register.html')


@auth_bp.route('/forgot-password', methods=['GET'])
def forgot_password_page():
    """Render the forgot password page."""
    return render_template('auth/forgot_password.html')


@auth_bp.route('/reset-password', methods=['GET'])
def reset_password_page():
    """Render the reset password page."""
    user_id = request.args.get('userId', '')
    secret = request.args.get('secret', '')

    return render_template('auth/reset_password.html', user_id=user_id, secret=secret)
