<?php

namespace WPSN\Modules\IndexNow;

use WPSN\Core\Http\HttpClient;
use WPSN\Core\Logger;

defined('ABSPATH') || exit;

final class IndexNowClient
{
    private Logger $logger;

    public function __construct(Logger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * Submit a payload to the IndexNow endpoint.
     *
     * @param string $endpoint
     * @param array<string,mixed> $body
     * @return array{ok:bool,status:int,error?:string,json?:array<string,mixed>,raw?:string}
     */
    public function submit(string $endpoint, array $body): array
    {
        $endpoint = trim($endpoint);
        if ($endpoint === '') {
            return ['ok' => false, 'status' => 0, 'error' => 'Missing endpoint'];
        }

        $args = [
            'timeout' => 15,
            'headers' => [
                'Content-Type' => 'application/json; charset=utf-8',
                'Accept'       => 'application/json',
                'User-Agent'   => 'WP-SEO-Next/' . (defined('WPSN_VERSION') ? WPSN_VERSION : 'dev') . ' (+https://wordpress.org)',
                // Mark for Privacy module logging.
                'X-WPSN-Service' => 'indexnow',
                'X-WPSN-Context' => 'submit',
            ],
            'body' => wp_json_encode($body),
        ];

        $resp = HttpClient::post($endpoint, $args, [
            'service' => 'indexnow',
            'context' => 'submit',
            'retries' => 1,
            'retry_statuses' => [429, 500, 502, 503, 504],
        ]);

        if (is_wp_error($resp)) {
            $msg = $resp->get_error_message();
            $data = $resp->get_error_data();
            if (is_array($data) && !empty($data['retry_after'])) {
                $msg .= ' (retry in ' . (int) $data['retry_after'] . 's)';
            }
            $this->logger->error('IndexNow request failed: ' . $msg);
            return ['ok' => false, 'status' => 0, 'error' => $msg];
        }

        $status = (int) wp_remote_retrieve_response_code($resp);
        $raw = (string) wp_remote_retrieve_body($resp);

        $json = null;
        if ($raw !== '') {
            $decoded = json_decode($raw, true);
            if (is_array($decoded)) {
                $json = $decoded;
            }
        }

        // IndexNow endpoints commonly return 200 or 202 on success.
        if ($status >= 200 && $status < 300) {
            return [
                'ok' => true,
                'status' => $status,
                'json' => is_array($json) ? $json : [],
                'raw' => $raw,
            ];
        }

        // Use JSON error message if possible.
        $err = '';
        if (is_array($json)) {
            $err = isset($json['message']) ? (string) $json['message'] : '';
            if ($err === '' && isset($json['error'])) {
                $err = is_string($json['error']) ? $json['error'] : wp_json_encode($json['error']);
            }
        }
        if (!is_string($err) || $err === '') {
            $err = $raw !== '' ? $raw : ('HTTP ' . $status);
        }

        return [
            'ok' => false,
            'status' => $status,
            'error' => $err,
            'json' => is_array($json) ? $json : [],
            'raw' => $raw,
        ];
    }


    /**
     * Lightweight GET ping request (used for sitemap ping endpoints).
     *
     * @return array{ok:bool,status:int,error:string,raw:string}
     */
    public function ping(string $url, int $timeout = 10): array
    {
        $url = trim($url);
        $url = $url !== '' ? esc_url_raw($url) : '';
        if ($url === '' || !wp_http_validate_url($url)) {
            return ['ok' => false, 'status' => 0, 'error' => 'Invalid URL', 'raw' => ''];
        }

        $args = [
            'timeout' => max(1, $timeout),
            'redirection' => 3,
            'headers' => [
                'User-Agent' => 'WP-SEO-Next/' . (defined('WPSN_VERSION') ? WPSN_VERSION : 'dev') . ' (+https://wordpress.org)',
                'Accept' => '*/*',
                // Mark for Privacy module logging.
                'X-WPSN-Service' => 'sitemap_ping',
                'X-WPSN-Context' => 'ping',
            ],
        ];

        $resp = HttpClient::get($url, $args, [
            'service' => 'sitemap_ping',
            'context' => 'ping',
            'retries' => 1,
            'retry_statuses' => [429, 500, 502, 503, 504],
        ]);

        if (is_wp_error($resp)) {
            $msg = $resp->get_error_message();
            $data = $resp->get_error_data();
            if (is_array($data) && !empty($data['retry_after'])) {
                $msg .= ' (retry in ' . (int) $data['retry_after'] . 's)';
            }
            $this->logger->error('Sitemap ping failed: ' . $msg);
            return ['ok' => false, 'status' => 0, 'error' => $msg, 'raw' => ''];
        }

        $status = (int) wp_remote_retrieve_response_code($resp);
        $raw = (string) wp_remote_retrieve_body($resp);

        if ($status >= 200 && $status < 300) {
            return ['ok' => true, 'status' => $status, 'error' => '', 'raw' => $raw];
        }

        $err = $raw !== '' ? $raw : ('HTTP ' . $status);
        return ['ok' => false, 'status' => $status, 'error' => $err, 'raw' => $raw];
    }
}
