<?php
/**
 * LinkCentral Geolocation
 *
 * Handles geolocation services for premium users.
 */
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

class LinkCentral_Geolocation {
    private $visitor_manager;

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

    /**
     * Get the user's full location (country, region, city).
     *
     * @return array {
     *   @type string $country Two-letter country code (ISO 3166-1 alpha-2) or empty string.
     *   @type string $region  Region, state, or province name or empty string.
     *   @type string $city    City name or empty string.
     * }
     */
    public function get_user_location() {
        // Check cache first
        $cached_location = $this->visitor_manager->get_cached('user_location');
        if ($cached_location !== null && is_array($cached_location)) {
            return $cached_location;
        }

        $geolocation_service = get_option('linkcentral_geolocation_service', 'none');

        $location = array(
            'country' => '',
            'region'  => '',
            'city'    => '',
        );

        switch ($geolocation_service) {
            case 'cloudflare':
                $location = $this->get_location_from_cloudflare();
                break;
            case 'maxmind':
                $location = $this->get_location_from_maxmind();
                break;
            default:
                // Leave default empty location.
                break;
        }

        // Normalize to ensure all expected keys exist.
        $location = wp_parse_args(
            is_array($location) ? $location : array(),
            array(
                'country' => '',
                'region'  => '',
                'city'    => '',
            )
        );

        // Cache the full location for this request.
        $this->visitor_manager->set_cached('user_location', $location);

        return $location;
    }

    /**
     * Get full location (country, region, city) from Cloudflare headers.
     *
     * Relies on Cloudflare's IP geolocation and location header transforms.
     */
    private function get_location_from_cloudflare() {
        $country = isset($_SERVER['HTTP_CF_IPCOUNTRY'])
            ? sanitize_text_field(wp_unslash($_SERVER['HTTP_CF_IPCOUNTRY']))
            : '';

        // CF-Region provides a human-readable region/state name.
        $region = isset($_SERVER['HTTP_CF_REGION'])
            ? sanitize_text_field(wp_unslash($_SERVER['HTTP_CF_REGION']))
            : '';

        // CF-IPCity provides a human-readable city name.
        $city = isset($_SERVER['HTTP_CF_IPCITY'])
            ? sanitize_text_field(wp_unslash($_SERVER['HTTP_CF_IPCITY']))
            : '';

        return array(
            'country' => $country,
            'region'  => $region,
            'city'    => $city,
        );
    }

    /**
     * Get full location (country, region, city) using MaxMind GeoIP2.
     *
     * Prefers the GeoLite2-City database when available and falls back
     * to the existing GeoLite2-Country database for country-only resolution.
     */
    private function get_location_from_maxmind() {
        $upload_dir = wp_upload_dir();

        $base_dir = trailingslashit($upload_dir['basedir']) . 'linkcentral';
        $city_database_path    = $base_dir . '/GeoLite2-City/GeoLite2-City.mmdb';
        $country_database_path = $base_dir . '/GeoLite2-Country/GeoLite2-Country.mmdb';

        $location = array(
            'country' => '',
            'region'  => '',
            'city'    => '',
        );

        try {
            require_once LINKCENTRAL_PLUGIN_DIR . 'vendor/autoload.php';

            $ip_address = $this->visitor_manager->get_ip_address();
            if (empty($ip_address)) {
                return $location;
            }

            // Prefer the City database if available for richer data.
            if (file_exists($city_database_path)) {
                $reader = new \GeoIp2\Database\Reader($city_database_path);
                $record = $reader->city($ip_address);

                $location['country'] = $record->country->isoCode ?: '';
                $location['region']  = $record->mostSpecificSubdivision->name ?: '';
                $location['city']    = $record->city->name ?: '';

                return $location;
            }

            // Fall back to country-only behavior.
            if (file_exists($country_database_path)) {
                $reader = new \GeoIp2\Database\Reader($country_database_path);
                $record = $reader->country($ip_address);
                $location['country'] = $record->country->isoCode ?: '';
            }
        } catch (\Exception $e) {
            // Swallow exceptions and fall back to empty/default location.
            return $location;
        }

        return $location;
    }

}
