import secrets
import time
from functools import wraps
from flask import session, abort, request, redirect, url_for, flash
from passlib.hash import pbkdf2_sha256
from modules.database import query_db, execute_db
from modules.logger import logger

def hash_password(password: str) -> str:
    """Hashes a password using PBKDF2 SHA256 (very compatible with cPanel)."""
    return pbkdf2_sha256.hash(password)

def verify_password(password: str, hashed: str) -> bool:
    """Verifies a password against its PBKDF2 hash."""
    try:
        return pbkdf2_sha256.verify(password, hashed)
    except Exception as e:
        logger.error(f"Password verification error: {e}")
        return False

def log_login_attempt(username: str, ip: str, status: str):
    """Logs a login attempt to the SQLite database."""
    try:
        execute_db(
            "INSERT INTO login_logs (username, ip_address, status, timestamp) VALUES (?, ?, ?, datetime('now'))",
            (username, ip, status)
        )
    except Exception as e:
        logger.error(f"Failed to log login attempt: {e}")

def is_ip_blocked(ip: str) -> bool:
    """Checks if an IP is temporarily blocked due to brute-force attempts.
    
    Rule: 5 failed attempts within the last 15 minutes.
    """
    try:
        # Check failures in last 15 minutes
        query = """
            SELECT COUNT(*) as fail_count FROM login_logs
            WHERE ip_address = ? AND status = 'Failed'
            AND timestamp > datetime('now', '-15 minutes')
        """
        result = query_db(query, (ip,), one=True)
        if result and result['fail_count'] >= 5:
            # Check if there is a successful login after the last failure
            success_query = """
                SELECT timestamp FROM login_logs
                WHERE ip_address = ? AND status = 'Success'
                ORDER BY timestamp DESC LIMIT 1
            """
            success = query_db(success_query, (ip,), one=True)
            if not success:
                return True
            
            # If there was a success, check if there are 5 failures AFTER the success
            fail_after_success = query_db("""
                SELECT COUNT(*) as fail_count FROM login_logs
                WHERE ip_address = ? AND status = 'Failed'
                AND timestamp > ?
            """, (ip, success['timestamp']), one=True)
            if fail_after_success and fail_after_success['fail_count'] >= 5:
                return True
        return False
    except Exception as e:
        logger.error(f"Error checking IP block status: {e}")
        return False

def generate_csrf_token() -> str:
    """Generates a secure CSRF token and stores it in the session."""
    if '_csrf_token' not in session:
        session['_csrf_token'] = secrets.token_hex(32)
    return session['_csrf_token']

def csrf_protect(f):
    """Decorator to protect POST requests against CSRF."""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if request.method == "POST":
            # Don't enforce CSRF check on the installer routes unless initialized
            if request.path.startswith('/install') and not session.get('installed', False):
                # Install routes are open before install completion
                return f(*args, **kwargs)
                
            token = request.form.get('_csrf_token') or request.headers.get('X-CSRF-Token')
            if not token or token != session.get('_csrf_token'):
                logger.warning(f"CSRF violation from IP: {request.remote_addr}")
                abort(403, "CSRF token validation failed. Please refresh the page.")
        return f(*args, **kwargs)
    return decorated_function

def login_required(f):
    """Decorator to restrict access to authenticated users."""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not session.get('logged_in'):
            flash("Please log in to access this page.", "danger")
            return redirect(url_for('login', next=request.url))
        return f(*args, **kwargs)
    return decorated_function

def sanitize_input(value: str) -> str:
    """Simple helper to prevent basic XSS."""
    if not isinstance(value, str):
        return value
    return value.replace("<", "&lt;").replace(">", "&gt;").replace('"', "&quot;").replace("'", "&#x27;")
