<?php

declare(strict_types=1);

namespace CliqThemes\StoreLocator\Geocoding;

defined('ABSPATH') || exit;

/**
 * Google Maps Geocoding API backend. Requires an API key with the Geocoding
 * API enabled.
 */
final class GoogleGeocoder implements GeocoderInterface
{
    private const ENDPOINT = 'https://maps.googleapis.com/maps/api/geocode/json';

    public function __construct(private readonly string $apiKey)
    {
    }

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

    public function geocode(string $address): ?GeocodeResult
    {
        return $this->lookup(['address' => $address]);
    }

    public function reverse(float $latitude, float $longitude): ?GeocodeResult
    {
        return $this->lookup(['latlng' => $latitude . ',' . $longitude]);
    }

    /**
     * @param array<string, string> $args
     */
    private function lookup(array $args): ?GeocodeResult
    {
        if ($this->apiKey === '') {
            return null;
        }

        $url = add_query_arg(array_merge($args, ['key' => $this->apiKey]), self::ENDPOINT);

        $response = wp_remote_get($url, ['timeout' => 8]);
        if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
            return null;
        }

        $data = json_decode(wp_remote_retrieve_body($response), true);
        if (! is_array($data) || ($data['status'] ?? '') !== 'OK' || empty($data['results'][0])) {
            return null;
        }

        $hit = $data['results'][0];
        $location = $hit['geometry']['location'] ?? [];

        return new GeocodeResult(
            (float) ($location['lat'] ?? 0),
            (float) ($location['lng'] ?? 0),
            (string) ($hit['formatted_address'] ?? ''),
            is_array($hit['address_components'] ?? null) ? $hit['address_components'] : []
        );
    }
}
