<?php

if (!defined('ABSPATH')) {
    exit;
}

class AIEO_Google_Reviews_Fetcher {

    const DETAILS_URL = 'https://maps.googleapis.com/maps/api/place/details/json';

    
    public static function fetch_one(array $location) {
        $api_key = AIEO_Google_Reviews_Settings::api_key_for_location($location);
        if ($api_key === '') {
            return self::record_failure($location, 'no_api_key', __('No API key configured (per-location or global).', 'ai-eshop-optimizer'));
        }
        $place_id = (string) ($location['place_id'] ?? '');
        if ($place_id === '' || strpos($place_id, 'ChIJ') !== 0) {
            return self::record_failure($location, 'invalid_place_id', __('place_id must be a Google ChIJ… identifier. Resolve the location first.', 'ai-eshop-optimizer'));
        }
        $language = (string) ($location['language'] ?? 'el');
        if ($language === '') { $language = 'el'; }

        $url = self::DETAILS_URL
            . '?place_id=' . rawurlencode($place_id)
            . '&fields='   . rawurlencode('name,rating,reviews,user_ratings_total,formatted_address,business_status,address_components,geometry,opening_hours,international_phone_number')
            . '&language=' . rawurlencode($language)
            . '&reviews_sort=newest'
            . '&reviews_no_translations=false'
            . '&key='      . rawurlencode($api_key);

        $resp = wp_remote_get($url, array(
            'timeout' => 25,
            'headers' => array('Accept' => 'application/json'),
        ));
        if (is_wp_error($resp)) {
            return self::record_failure($location, 'network', $resp->get_error_message());
        }
        $code = (int) wp_remote_retrieve_response_code($resp);
        $body = (string) wp_remote_retrieve_body($resp);
        $json = json_decode($body, true);
        if ($code !== 200 || !is_array($json)) {
            
            return self::record_failure($location, 'http_' . $code, sprintf(__('HTTP %d', 'ai-eshop-optimizer'), $code));
        }
        $status = (string) ($json['status'] ?? 'UNKNOWN');
        if ($status !== 'OK') {
            $msg = isset($json['error_message']) ? (string) $json['error_message'] : $status;
            return self::record_failure($location, $status, $msg);
        }

        $result = isset($json['result']) && is_array($json['result']) ? $json['result'] : array();
        $reviews = isset($result['reviews']) && is_array($result['reviews']) ? $result['reviews'] : array();

        $inserted = 0;
        foreach ($reviews as $r) {
            if (!is_array($r)) { continue; }
            if (self::insert_review_if_new((int) $location['id'], $r)) {
                $inserted++;
            }
        }

        
        
        
        
        $rating = isset($result['rating']) ? (float) $result['rating'] : null;
        $count  = isset($result['user_ratings_total']) ? (int) $result['user_ratings_total'] : null;

        AIEO_Google_Reviews_Locations::record_fetch_result((int) $location['id'], 'OK', array_merge(array(
            'rating'       => $rating,
            'review_count' => $count,
            'google_name'  => (string) ($result['name'] ?? ''),
            'address'      => (string) ($result['formatted_address'] ?? ''),
        ), self::parse_place_supplement($result)));

        
        
        AIEO_Google_Reviews_Cache::bump_version((int) $location['id']);

        return array(
            'ok'           => true,
            'status'       => 'OK',
            'fetched'      => count($reviews),
            'inserted'     => $inserted,
            'rating'       => $rating,
            'review_count' => $count,
        );
    }

    
    public static function fetch_all_enabled($enforce_rate_limit = true) {
        $locations = AIEO_Google_Reviews_Locations::list_all(true); 
        $totals = array(
            'locations'      => 0,
            'fetched'        => 0,
            'inserted'       => 0,
            'errors'         => 0,
            'skipped'        => 0,
            'error_messages' => array(),
        );
        foreach ($locations as $loc) {
            $totals['locations']++;
            if ($enforce_rate_limit && !self::rate_limit_ok()) {
                $totals['skipped']++;
                continue;
            }
            $r = self::fetch_one($loc);
            self::note_api_call();
            if (empty($r['ok'])) {
                $totals['errors']++;
                if (count($totals['error_messages']) < 10) {
                    $label = isset($loc['label']) ? $loc['label'] : ('#' . (int) ($loc['id'] ?? 0));
                    $totals['error_messages'][] = sprintf('%s: %s', $label, (string) ($r['error'] ?? $r['status'] ?? 'error'));
                }
                continue;
            }
            $totals['fetched']  += (int) ($r['fetched']  ?? 0);
            $totals['inserted'] += (int) ($r['inserted'] ?? 0);
        }
        return $totals;
    }

    
    private static function rate_limit_ok() {
        $c = self::call_counts();
        return ($c['hour'] < (int) AIEO_Google_Reviews_Settings::get('rate_limit_per_hour', 20))
            && ($c['day']  < (int) AIEO_Google_Reviews_Settings::get('rate_limit_per_day', 500));
    }

    
    private static function call_counts() {
        $hk = gmdate('YmdH');
        $dk = gmdate('Ymd');
        $st = get_option('aieo_grv_api_calls', array());
        return array(
            'hk'   => $hk,
            'dk'   => $dk,
            'hour' => (isset($st['hk']) && $st['hk'] === $hk) ? (int) $st['hc'] : 0,
            'day'  => (isset($st['dk']) && $st['dk'] === $dk) ? (int) $st['dc'] : 0,
        );
    }

    
    private static function note_api_call() {
        $c = self::call_counts();
        update_option('aieo_grv_api_calls', array(
            'hk' => $c['hk'], 'hc' => $c['hour'] + 1,
            'dk' => $c['dk'], 'dc' => $c['day'] + 1,
        ), false);
    }

    
    private static function parse_place_supplement(array $result) {
        $out = array();

        if (isset($result['geometry']['location']['lat'], $result['geometry']['location']['lng'])) {
            $out['lat'] = (float) $result['geometry']['location']['lat'];
            $out['lng'] = (float) $result['geometry']['location']['lng'];
        }

        if (!empty($result['address_components']) && is_array($result['address_components'])) {
            $comp = $result['address_components'];
            $get  = static function ($type, $short = false) use ($comp) {
                foreach ($comp as $c) {
                    if (!empty($c['types']) && in_array($type, (array) $c['types'], true)) {
                        return (string) ($short ? ($c['short_name'] ?? '') : ($c['long_name'] ?? ''));
                    }
                }
                return '';
            };
            $route  = $get('route');
            $number = $get('street_number');
            
            $street = trim($route . ('' !== $number ? ' ' . $number : ''));
            if ('' !== $street)   { $out['street']   = $street; }
            $locality = $get('locality');
            if ('' === $locality) { $locality = $get('postal_town'); }
            if ('' !== $locality) { $out['locality'] = $locality; }
            $region = $get('administrative_area_level_1');
            if ('' === $region)   { $region = $get('administrative_area_level_2'); }
            if ('' !== $region)   { $out['region']   = $region; }
            $postal = $get('postal_code');
            if ('' !== $postal)   { $out['postcode'] = $postal; }
            $country = $get('country', true);
            if ('' !== $country)  { $out['country']  = strtoupper(substr($country, 0, 2)); }
        }

        
        
        if (!empty($result['opening_hours']['periods']) && is_array($result['opening_hours']['periods'])) {
            $out['hours_json'] = wp_json_encode($result['opening_hours']['periods']);
        }

        if (!empty($result['international_phone_number'])) {
            $out['phone'] = (string) $result['international_phone_number'];
        }

        return $out;
    }

    
    private static function insert_review_if_new($location_id, array $r) {
        global $wpdb;
        $tbl = $wpdb->prefix . 'aieo_google_reviews';

        $author_name = (string) ($r['author_name'] ?? '');
        $rating      = max(0, min(5, (int) ($r['rating'] ?? 0)));
        $time        = (int) ($r['time'] ?? 0);
        $text        = (string) ($r['text'] ?? '');

        if ($author_name === '' || $time <= 0 || $rating <= 0) {
            return false;
        }

        $hash = hash('sha256', sprintf(
            '%s|%d|%d|%s',
            $author_name,
            $time,
            $rating,
            substr($text, 0, 500)
        ));

        
        $existing = (int) $wpdb->get_var($wpdb->prepare(
            "SELECT id FROM {$tbl} WHERE location_id = %d AND review_hash = %s LIMIT 1",
            (int) $location_id, $hash
        ));
        if ($existing > 0) { return false; }

        
        
        
        $row = array(
            'location_id'          => (int) $location_id,
            'review_hash'          => $hash,
            'author_name'          => self::trunc_utf8($author_name, 190),
            'author_url'           => self::trunc_utf8((string) ($r['author_url'] ?? ''), 500),
            'profile_photo_url'    => self::trunc_utf8((string) ($r['profile_photo_url'] ?? ''), 500),
            'rating'               => $rating,
            'review_text'          => $text !== '' ? $text : null,
            'review_text_original' => isset($r['original_text']) ? (string) $r['original_text'] : null,
            'language'             => isset($r['language']) ? self::trunc_utf8((string) $r['language'], 10) : null,
            'original_language'    => isset($r['original_language']) ? self::trunc_utf8((string) $r['original_language'], 10) : null,
            'relative_time'        => self::trunc_utf8((string) ($r['relative_time_description'] ?? ''), 60),
            'review_time'          => $time,
            'raw_json'             => wp_json_encode($r),
        );

        
        
        
        $formats = array(
            '%d', 
            '%s', 
            '%s', 
            '%s', 
            '%s', 
            '%d', 
            '%s', 
            '%s', 
            '%s', 
            '%s', 
            '%s', 
            '%d', 
            '%s', 
        );

        $ok = $wpdb->insert($tbl, $row, $formats);
        return $ok !== false && $wpdb->insert_id > 0;
    }

    
    private static function trunc_utf8($s, $max_chars) {
        $s = (string) $s;
        if ($s === '' || $max_chars <= 0) { return ''; }
        if (function_exists('mb_substr')) {
            return mb_substr($s, 0, (int) $max_chars, 'UTF-8');
        }
        return substr($s, 0, (int) $max_chars);
    }

    private static function record_failure(array $location, $status, $error_text) {
        if (!empty($location['id'])) {
            AIEO_Google_Reviews_Locations::record_fetch_result((int) $location['id'], $status, array(
                'error_text' => $error_text,
            ));
        }
        return array(
            'ok'       => false,
            'status'   => (string) $status,
            'fetched'  => 0,
            'inserted' => 0,
            'error'    => (string) $error_text,
        );
    }
}
