<?php
/**
 * HOSTIVA V3 — PASSWORD RESET CONTROLLER
 * ======================================
 * 
 * Features:
 * - Safe password reset token generation
 * - Token expiration (1 hour)
 * - IP and user agent tracking
 * - Rate limiting per email
 * - Secure password hashing
 * 
 * Routes:
 * - POST /api/auth/password-reset/request
 * - POST /api/auth/password-reset/validate
 * - POST /api/auth/password-reset/complete
 */

$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$action = trim($_GET['action'] ?? $_POST['action'] ?? '', '/');

// ===== REQUEST RESET =====
if ($action === 'password-reset/request' && $method === 'POST') {
    rate_limit('password_reset_request', 5); // 5 per minute
    
    $d = input();
    $email = strtolower(trim((string)($d['email'] ?? '')));
    
    if (!v_email($email)) {
        json_error('Valid email is required', 422);
    }
    
    try {
        // Find user by email
        $stmt = db()->prepare('
            SELECT id, email, name FROM users 
            WHERE email=? AND deleted_at IS NULL 
            LIMIT 1
        ');
        $stmt->execute([$email]);
        $user = $stmt->fetch();
        
        if (!$user) {
            // Don't reveal if email exists (security best practice)
            audit('password_reset.request.fail', 'user', null, 'Email not found: ' . $email);
            json_ok([], 'If an account exists, reset instructions will be sent');
            return;
        }
        
        // Generate reset token (valid for 1 hour)
        $token = bin2hex(random_bytes(32));
        $expiresAt = date('Y-m-d H:i:s', time() + 3600);
        
        // Store reset token in database
        $stmt = db()->prepare('
            INSERT INTO password_resets (user_id, token, expires_at, ip, user_agent)
            VALUES (?, ?, ?, ?, ?)
            ON DUPLICATE KEY UPDATE 
                token=VALUES(token),
                expires_at=VALUES(expires_at),
                ip=VALUES(ip),
                user_agent=VALUES(user_agent),
                used_at=NULL,
                created_at=NOW()
        ');
        $stmt->execute([
            $user['id'],
            hash('sha256', $token),
            $expiresAt,
            $_SERVER['REMOTE_ADDR'] ?? null,
            substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 250)
        ]);
        
        // Log request
        audit('password_reset.request', 'user', $user['id'], 'Reset requested', [
            'ip' => $_SERVER['REMOTE_ADDR'] ?? null
        ]);
        
        // In production, send email here
        // For now, just return success
        // TODO: Integrate email service
        // email_send_password_reset($user['email'], $user['name'], $token);
        
        json_ok([], 'If an account exists, reset instructions will be sent');
        
    } catch (Throwable $e) {
        error_log('Password reset request failed: ' . $e->getMessage());
        json_error('Server error', 500);
    }
}

// ===== VALIDATE TOKEN =====
else if ($action === 'password-reset/validate' && $method === 'POST') {
    rate_limit('password_reset_validate', 10);
    
    $d = input();
    $token = trim((string)($d['token'] ?? ''));
    
    if (!$token) {
        json_error('Reset token is required', 422);
    }
    
    try {
        $tokenHash = hash('sha256', $token);
        
        // Find valid reset request
        $stmt = db()->prepare('
            SELECT pr.user_id, pr.expires_at, u.email 
            FROM password_resets pr
            JOIN users u ON u.id=pr.user_id
            WHERE pr.token=? 
                AND pr.expires_at > NOW()
                AND pr.used_at IS NULL
                AND u.deleted_at IS NULL
            LIMIT 1
        ');
        $stmt->execute([$tokenHash]);
        $reset = $stmt->fetch();
        
        if (!$reset) {
            audit('password_reset.validate.fail', 'user', null, 'Invalid or expired token');
            json_error('Invalid or expired reset token', 400);
        }
        
        json_ok([
            'valid' => true,
            'email' => $reset['email']
        ]);
        
    } catch (Throwable $e) {
        error_log('Token validation failed: ' . $e->getMessage());
        json_error('Server error', 500);
    }
}

// ===== COMPLETE RESET =====
else if ($action === 'password-reset/complete' && $method === 'POST') {
    rate_limit('password_reset_complete', 3);
    
    $d = input();
    $token = trim((string)($d['token'] ?? ''));
    $password = (string)($d['password'] ?? '');
    $passwordConfirm = (string)($d['password_confirm'] ?? '');
    
    // Validate input
    if (!$token) {
        json_error('Reset token is required', 422);
    }
    
    if (!$password) {
        json_error('New password is required', 422);
    }
    
    if ($password !== $passwordConfirm) {
        json_error('Passwords do not match', 422);
    }
    
    v_password($password); // Validates and throws on invalid
    
    try {
        $tokenHash = hash('sha256', $token);
        
        db()->beginTransaction();
        
        // Find valid reset request (with lock)
        $stmt = db()->prepare('
            SELECT pr.user_id, pr.expires_at 
            FROM password_resets pr
            WHERE pr.token=? 
                AND pr.expires_at > NOW()
                AND pr.used_at IS NULL
            LIMIT 1
            FOR UPDATE
        ');
        $stmt->execute([$tokenHash]);
        $reset = $stmt->fetch();
        
        if (!$reset) {
            db()->rollBack();
            audit('password_reset.complete.fail', 'user', null, 'Invalid or expired token');
            json_error('Invalid or expired reset token', 400);
        }
        
        // Hash new password
        $hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
        
        // Update user password
        $stmt = db()->prepare('
            UPDATE users 
            SET password=?, 
                failed_logins=0,
                locked_until=NULL,
                updated_at=NOW()
            WHERE id=?
        ');
        $stmt->execute([$hash, $reset['user_id']]);
        
        // Mark reset as used
        $stmt = db()->prepare('
            UPDATE password_resets 
            SET used_at=NOW()
            WHERE token=?
        ');
        $stmt->execute([$tokenHash]);
        
        db()->commit();
        
        audit('password_reset.complete', 'user', $reset['user_id'], 'Password reset successfully');
        
        json_ok([], 'Password reset successfully. You can now log in.');
        
    } catch (Throwable $e) {
        db()->rollBack();
        error_log('Password reset completion failed: ' . $e->getMessage());
        json_error('Server error', 500);
    }
}

// ===== NO ACTION MATCHED =====
else {
    json_error('Invalid password reset action', 404);
}
