<?php

namespace Formatrica\Submission\Integrations\Dispatchers;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use Formatrica\Submission\Integrations\Http_Client;
use Formatrica\Submission\Integrations\Integration_Dispatcher_Interface;
use Formatrica\Submission\Security\Endpoint_Validator;
use Formatrica\Support\Secrets;

/**
 * Dispatcher for general webhooks with HMAC signing
 */
final class Webhook_Dispatcher implements Integration_Dispatcher_Interface
{
    private Endpoint_Validator $validator;

    public function __construct(?Endpoint_Validator $validator = null)
    {
        $this->validator = $validator ?? new Endpoint_Validator();
    }

    public function dispatch(array $settings, array $form, array $payload, array $context, array $field_meta): void
    {
        $endpoint = isset($settings['endpoint']) ? esc_url_raw($settings['endpoint']) : '';

        if ($endpoint === '') {
            return;
        }

        $secret = Secrets::decrypt($settings['secret'] ?? '');

        $target = $this->validator->validate($endpoint);
        if ($target === null) {
            return;
        }

        $body = [
            'form' => [
                'id' => $form['id'],
                'title' => $form['title'],
            ],
            'submission' => $payload,
            'meta' => $field_meta,
            'context' => $context,
            'integration' => 'webhook',
        ];

        $body = apply_filters('formatrica_webhook_payload', $body, $form, $payload, $context, $field_meta);
        $json = wp_json_encode($body);

        if (false === $json) {
            return;
        }

        $headers = [
            'Content-Type' => 'application/json',
        ];

        if ($secret !== '') {
            $headers['X-Formatrica-Signature'] = hash_hmac('sha256', $json, $secret);
        }

        $args = [
            'method' => 'POST',
            'body' => $json,
            'headers' => $headers,
            'timeout' => 10,
            'redirection' => 0, // no redirects: target is SSRF-validated pre-flight (avoid TOCTOU)
            'reject_unsafe_urls' => true,
            'blocking' => true,
            'limit_response_size' => 512 * 1024,
        ];

        $response = wp_remote_post($target, $args);

        if (is_wp_error($response)) {
            $this->log_error($target, $response->get_error_message(), $form, $payload, $context);
            return;
        }

        $code = (int) wp_remote_retrieve_response_code($response);
        if ($code < 200 || $code >= 400) {
            $this->log_error(
                $target,
                sprintf('HTTP %d', $code),
                $form,
                $payload,
                $context
            );
        }
    }

    /**
     * @param string $endpoint
     * @param string $message
     * @param array<string, mixed> $form
     * @param array<string, mixed> $payload
     * @param array<string, mixed> $context
     */
    private function log_error(string $endpoint, string $message, array $form, array $payload, array $context): void
    {
        do_action('formatrica_webhook_failed', [
            'endpoint' => $endpoint,
            'integration' => 'webhook',
            'error' => $message,
            'context' => $context,
        ], $form, $payload);
        do_action('formatrica_debug_log', sprintf('Webhook request failed for %s - %s', $endpoint, $message));
    }
}
