"""
VYNDR Authentication Middleware
Verifies Supabase JWT tokens on all protected endpoints.
Internal key validation for cron/service endpoints.
"""

import os
import logging
import functools
from flask import request, jsonify

logger = logging.getLogger('vyndr')

SUPABASE_JWT_SECRET = os.environ.get('SUPABASE_JWT_SECRET', '')
SUPABASE_URL = os.environ.get('SUPABASE_URL', '')

# Service-role key. Read VYNDR_INTERNAL_KEY first, fall back to the legacy
# BETONBLK_INTERNAL_KEY so deployed Railway secrets keep working until the
# operator renames the env var. Both names accepted during the transition.
INTERNAL_KEY = os.environ.get('VYNDR_INTERNAL_KEY') or os.environ.get('BETONBLK_INTERNAL_KEY', '')


def verify_jwt(token):
    """
    Verify a Supabase JWT token with issuer check.

    Args:
        token: JWT token string.

    Returns:
        Decoded payload dict if valid, None if invalid.
    """
    if not SUPABASE_JWT_SECRET:
        logger.warning('[Auth] JWT secret not configured — skipping verification')
        return {'sub': 'anonymous', 'role': 'authenticated'}

    try:
        import jwt
        kwargs = {
            'algorithms': ['HS256'],
            'audience': 'authenticated',
        }
        # Issuer check prevents cross-project token reuse
        if SUPABASE_URL:
            kwargs['issuer'] = SUPABASE_URL

        decoded = jwt.decode(token, SUPABASE_JWT_SECRET, **kwargs)
        return decoded
    except Exception as e:
        if 'ExpiredSignature' in type(e).__name__:
            logger.warning('[Auth] Expired token')
        else:
            logger.warning(f'[Auth] Invalid token: {e}')
        return None


def require_auth(f):
    """
    Decorator for user-facing endpoints.
    Extracts Bearer token from Authorization header.
    Attaches user info to Flask request context.
    """
    @functools.wraps(f)
    def decorated(*args, **kwargs):
        auth_header = request.headers.get('Authorization', '')

        if not auth_header.startswith('Bearer '):
            return jsonify({'error': 'Missing or invalid Authorization header'}), 401

        token = auth_header[7:]  # Strip 'Bearer '
        if not token:
            return jsonify({'error': 'Empty token'}), 401

        payload = verify_jwt(token)
        if not payload:
            return jsonify({'error': 'Invalid or expired token'}), 401

        request.user_id = payload.get('sub')
        request.user_role = payload.get('role', 'authenticated')
        request.user_email = payload.get('email', '')

        return f(*args, **kwargs)
    return decorated


def require_service_role(f):
    """
    Decorator for internal/cron endpoints.
    Validates the service-role internal key (read from VYNDR_INTERNAL_KEY,
    falling back to BETONBLK_INTERNAL_KEY during the env-var rename).
    The service key never leaves Railway. GitHub Actions crons use the
    internal key only.
    """
    @functools.wraps(f)
    def decorated(*args, **kwargs):
        api_key = request.headers.get('X-API-Key', '')

        if INTERNAL_KEY and api_key == INTERNAL_KEY:
            return f(*args, **kwargs)

        # Fallback: check Authorization Bearer against internal key
        auth_header = request.headers.get('Authorization', '')
        if auth_header.startswith('Bearer ') and INTERNAL_KEY:
            if auth_header[7:] == INTERNAL_KEY:
                return f(*args, **kwargs)

        return jsonify({'error': 'Unauthorized — service role required'}), 403
    return decorated


def get_real_ip():
    """
    Get real client IP accounting for Railway/proxy X-Forwarded-For header.

    Returns:
        Client IP string.
    """
    forwarded = request.headers.get('X-Forwarded-For', '')
    if forwarded:
        return forwarded.split(',')[0].strip()
    return request.remote_addr or '127.0.0.1'
