<?php

namespace FleekDash\Integrations\Core;

defined('ABSPATH') || exit;

/**
 * Signature / token validation for incoming integration webhooks.
 */
final class WebhookIncomingAuthenticator
{
    /**
     * @param array<string, mixed> $config
     */
    public function authenticate(\WP_REST_Request $request, array $config): bool|\WP_Error
    {
        $method = $config['authentication'] ?? '';
        $verified = true;

        if ($method === 'signature') {
            $verified = $this->verifySignature($request, (string) $config['secret']);
        } elseif ($method === 'token') {
            $verified = $this->verifyToken($request, (string) $config['secret']);
        } elseif ($method === 'none') {
            $verified = true;
        } else {
            $verified = new \WP_Error('invalid_auth', 'Invalid authentication method', ['status' => 401]);
        }

        return $verified;
    }

    private function verifySignature(\WP_REST_Request $request, string $secret): bool|\WP_Error
    {
        $signature = $request->get_header('X-Hub-Signature-256') ?: $request->get_header('X-FleekDash-Signature');

        if (!$signature) {
            return new \WP_Error('missing_signature', 'Missing signature header', ['status' => 401]);
        }

        $body = $request->get_body();
        $expectedSignature = 'sha256=' . hash_hmac('sha256', $body, $secret);

        if (!hash_equals($expectedSignature, $signature)) {
            return new \WP_Error('invalid_signature', 'Invalid signature', ['status' => 401]);
        }

        return true;
    }

    private function verifyToken(\WP_REST_Request $request, string $secret): bool|\WP_Error
    {
        $token = $request->get_header('Authorization') ?: $request->get_param('token');

        if (!$token) {
            return new \WP_Error('missing_token', 'Missing authentication token', ['status' => 401]);
        }

        $token = str_replace('Bearer ', '', $token);

        if (!hash_equals($secret, $token)) {
            return new \WP_Error('invalid_token', 'Invalid token', ['status' => 401]);
        }

        return true;
    }
}
