<?php

declare(strict_types=1);

namespace BotGuard\Services\Detection\Modules;

use BotGuard\Services\Detection\ModuleResult;
use BotGuard\Services\Detection\SignalBag;

/**
 * Keyboard-behaviour analysis module.
 *
 * When the challenge involves typing, human keystrokes have variable inter-key
 * intervals and natural corrections (backspaces). Instantaneous, uniform, or
 * paste-only input is bot-like. If the flow required no typing, absence of data
 * is neutral.
 */
final class KeyboardModule extends AbstractModule
{
    public function key(): string
    {
        return 'keyboard';
    }

    public function analyze(SignalBag $signals): ModuleResult
    {
        $kb = $signals->clientArray('keyboard');

        // No typing was required / performed — neutral-positive, do not penalise
        // (the default slider challenge involves no typing at all).
        if ($kb === [] || (int) ($kb['keydown_count'] ?? 0) === 0) {
            return $this->scored(0.8, [], [], ['present' => false]);
        }

        $count = (int) ($kb['keydown_count'] ?? 0);
        $intervalStd = (float) ($kb['interval_stddev_ms'] ?? 0);
        $avgInterval = (float) ($kb['avg_interval_ms'] ?? 0);
        $paste = (bool) ($kb['paste_detected'] ?? false);
        $backspaces = (int) ($kb['backspaces'] ?? 0);

        $this->detail('keydown_count', $count);
        $this->detail('avg_interval_ms', $avgInterval);
        $this->detail('interval_stddev_ms', $intervalStd);
        $this->detail('paste_detected', $paste);

        // Variable inter-key timing (constant cadence = scripted).
        $this->check('Variable key intervals', $intervalStd > 5.0, 2.0);

        // Human-plausible average cadence (not impossibly fast).
        $this->check('Human typing cadence', $avgInterval >= 40, 1.5);

        // Whole input pasted in one shot is suspicious for a challenge field.
        $this->check('Not paste-only entry', ! $paste || $count > 3, 1.0);

        // Natural corrections are a mild human signal.
        $this->check('Contains corrections/edits', $backspaces >= 0, 0.5);

        return $this->result();
    }
}
