"""
Password validation helpers: complexity checks and history checks.
"""
import re
import logging
from typing import List

from passlib.context import CryptContext

logger = logging.getLogger(__name__)
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


def validate_password_complexity(password: str, policy) -> List[str]:
    """
    Validates password against policy rules.
    Returns list of violation messages (empty list = passes all checks).
    """
    violations: List[str] = []
    if len(password) < policy.min_length:
        violations.append(f"Password must be at least {policy.min_length} characters.")
    if policy.require_uppercase and not re.search(r"[A-Z]", password):
        violations.append("Password must contain at least one uppercase letter.")
    if policy.require_lowercase and not re.search(r"[a-z]", password):
        violations.append("Password must contain at least one lowercase letter.")
    if policy.require_digit and not re.search(r"\d", password):
        violations.append("Password must contain at least one digit.")
    if policy.require_special and not re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
        violations.append("Password must contain at least one special character.")
    return violations


def check_password_history(db, user_id: int, new_password: str, history_count: int) -> bool:
    """
    Returns True if new_password matches any of the last history_count stored hashes.
    Uses bcrypt verification — no plaintext is stored or compared.

    SECURITY (MEDIUM): This function performs up to `history_count` bcrypt verifications
    per call (default 5, max 24 per schema). Each bcrypt verify is intentionally slow
    (~100ms at cost factor 12). At history_count=24, this is ~2.4 seconds of CPU per
    password-change request, which can be abused to exhaust server CPU (DoS).
    Mitigation options:
      1. Cap history_count at a lower value (5–10 is typical; 24 is excessive).
      2. Add rate limiting on PUT /users/me/password before this check runs.
      3. Consider Argon2id with tuned memory/time parameters for a better cost profile.
    """
    from sqlalchemy import select
    from src.apps.user_profile.models.password_history import UserPasswordHistory

    stmt = (
        select(UserPasswordHistory.hashed_password)
        .where(UserPasswordHistory.user_id == user_id)
        .order_by(UserPasswordHistory.created_at.desc())
        .limit(history_count)
    )
    history = db.execute(stmt).scalars().all()
    return any(pwd_context.verify(new_password, h) for h in history)
