<?php

declare(strict_types=1);

namespace CliqThemes\StoreLocator\Geocoding;

defined('ABSPATH') || exit;

/**
 * Free OpenStreetMap (Nominatim) geocoder — the default, no API key required.
 * Honours the Nominatim usage policy by sending a descriptive User-Agent and
 * limiting requests (callers should cache + throttle bulk operations).
 */
final class NominatimGeocoder implements GeocoderInterface
{
    private const SEARCH = 'https://nominatim.openstreetmap.org/search';
    private const REVERSE = 'https://nominatim.openstreetmap.org/reverse';

    public function id(): string
    {
        return 'nominatim';
    }

    public function geocode(string $address): ?GeocodeResult
    {
        $url = add_query_arg([
            'q' => $address,
            'format' => 'jsonv2',
            'limit' => 1,
            'addressdetails' => 1,
        ], self::SEARCH);

        $data = $this->request($url);

        if (! is_array($data) || empty($data[0])) {
            return null;
        }

        $hit = $data[0];

        return new GeocodeResult(
            (float) ($hit['lat'] ?? 0),
            (float) ($hit['lon'] ?? 0),
            (string) ($hit['display_name'] ?? ''),
            is_array($hit['address'] ?? null) ? $hit['address'] : []
        );
    }

    public function reverse(float $latitude, float $longitude): ?GeocodeResult
    {
        $url = add_query_arg([
            'lat' => $latitude,
            'lon' => $longitude,
            'format' => 'jsonv2',
            'addressdetails' => 1,
        ], self::REVERSE);

        $data = $this->request($url);

        if (! is_array($data) || empty($data['lat'])) {
            return null;
        }

        return new GeocodeResult(
            (float) $data['lat'],
            (float) $data['lon'],
            (string) ($data['display_name'] ?? ''),
            is_array($data['address'] ?? null) ? $data['address'] : []
        );
    }

    /**
     * @return mixed decoded JSON or null on failure
     */
    private function request(string $url): mixed
    {
        $response = wp_remote_get($url, [
            'timeout' => 8,
            'headers' => [
                'User-Agent' => 'CliqStoreLocator/1.0 (' . home_url('/') . ')',
                'Accept' => 'application/json',
            ],
        ]);

        if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
            return null;
        }

        return json_decode(wp_remote_retrieve_body($response), true);
    }
}
