<?php
if (!defined('ABSPATH')) exit;

class FORMFORGE_Webhooks {
    private static $instance = null;

    public static function instance() {
        if (!self::$instance) self::$instance = new self();
        return self::$instance;
    }

    private function __construct() {}

    public function fire_webhook($form, $data, $submission_id) {
        if (!FORMFORGE_License::instance()->can('webhooks')) {
            $this->log_webhook('skip', 'webhooks feature unavailable', ['form_id' => $form->id ?? 0]);
            return;
        }

        $url = $form->settings['webhook_url'] ?? '';
        if (empty($url) || !filter_var($url, FILTER_VALIDATE_URL)) {
            $this->log_webhook('skip', 'empty or invalid URL', ['form_id' => $form->id ?? 0]);
            return;
        }
        if (!$this->is_safe_url($url)) {
            $this->log_webhook('skip', 'blocked by URL safety policy', [
                'form_id' => $form->id ?? 0,
                'host' => wp_parse_url($url, PHP_URL_HOST),
            ]);
            return;
        }

        $payload = $this->build_payload($form, $data, $submission_id);
        $headers = array_merge(
            ['Content-Type' => 'application/json'],
            $this->parse_custom_headers($form->settings['webhook_headers'] ?? '')
        );

        $resp = wp_remote_post($url, [
            'body' => wp_json_encode($payload),
            'headers' => $headers,
            'timeout' => 10,
            'blocking' => true,
        ]);

        if (is_wp_error($resp)) {
            $this->log_webhook('error', $resp->get_error_message(), ['form_id' => $form->id ?? 0]);
            return;
        }

        $status = (int) wp_remote_retrieve_response_code($resp);
        $this->log_webhook($status >= 200 && $status < 300 ? 'ok' : 'error', 'status=' . $status, [
            'form_id' => $form->id ?? 0,
            'submission_id' => (int) $submission_id,
        ]);
    }

    private function build_payload($form, $data, $submission_id) {
        $payload = [
            'form_id'       => (int) $form->id,
            'form_title'    => $form->title,
            'submission_id' => (int) $submission_id,
            'timestamp'     => current_time('c'),
            'fields'        => [],
        ];

        foreach (FORMFORGE_Value_Formatter::submission_display_fields($data) as $id => $field) {
            $payload['fields'][$id] = [
                'label' => $field['label'] ?? $id,
                'value' => FORMFORGE_Value_Formatter::text($field['value'] ?? '', ''),
            ];
        }

        return $payload;
    }

    private function parse_custom_headers($raw_headers) {
        $headers = [];
        $blocked = ['host', 'content-length', 'content-type', 'connection', 'transfer-encoding'];
        foreach (preg_split('/\r\n|\r|\n/', (string) $raw_headers) as $line) {
            $line = trim($line);
            if ($line === '' || strpos($line, ':') === false) continue;
            [$name, $value] = array_map('trim', explode(':', $line, 2));
            $lower = strtolower($name);
            if (!preg_match('/^[A-Za-z0-9-]+$/', $name)) continue;
            if (in_array($lower, $blocked, true)) continue;
            $value = str_replace(["\r", "\n"], '', $value);
            if ($value === '') continue;
            $headers[$name] = sanitize_text_field($value);
        }
        return $headers;
    }

    private function log_webhook($status, $message, $context = []) {
        $entry = array_merge([
            'ts'      => time(),
            'status'  => sanitize_key((string) $status),
            'message' => sanitize_text_field((string) $message),
        ], is_array($context) ? $context : []);

        $log = (array) get_option('formforge_webhook_log', []);
        $log[] = $entry;
        if (count($log) > 30) $log = array_slice($log, -30);
        update_option('formforge_webhook_log', $log, false);
    }

    private function is_safe_url($url) {
        $parsed = wp_parse_url($url);
        $host = $parsed['host'] ?? '';
        $scheme = strtolower($parsed['scheme'] ?? '');

        if (!in_array($scheme, ['http', 'https'], true)) return false;
        if (in_array(strtolower($host), ['localhost', '127.0.0.1', '::1', '0.0.0.0'], true)) return false;

        $ip = gethostbyname($host);
        if ($ip === $host && !filter_var($host, FILTER_VALIDATE_IP)) return false;

        return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false;
    }
}
