<?php
require_once(__DIR__ . '/../vendor/autoload.php');

class IO_Reviews_Admin_Page
{
    public $candidates = [];

    public function handle_requests()
    {
        if ($_SERVER['REQUEST_METHOD'] === 'POST')
        {
            if (isset($_POST['clear_imported_reviews']))
                $this->clear_imported_reviews();
            elseif (isset($_POST['selected_place_id']))
            {
                $this->store_google_reviews_data();
                $this->check_reviews(); // Call check_reviews immediately after storing the place ID
                $_POST['active_tab'] = 'google-reviews'; // Set the active tab to Google Reviews
            }
            elseif (isset($_POST['review_type']))
                update_option('io_reviews_widget_type', $_POST['review_type']); // Save the selected review type
            elseif (isset($_POST['filter_rating']) || isset($_POST['filter_time']))
                $this->apply_filters();
            elseif (isset($_POST['check_reviews']) && get_option('io_reviews_myplaceID'))
                $this->check_reviews();
            elseif (isset($_POST['business_name']) && !isset($_POST['selected_place_id']))
                $this->search_business();
        }
    }

    private function clear_imported_reviews()
    {
        delete_option('io_reviews_google');
        delete_option('io_reviews_myplaceID');
        update_option('io_reviews_widget_type', 'io_testimonials');
    }

    private function store_google_reviews_data()
    {
        $placeId = $_POST['selected_place_id'];
        $rating = isset($_POST['avg_rating']) ? (float)$_POST['avg_rating'] : 0;
        $userRatingsTotal = isset($_POST['total_reviews']) ? (int)$_POST['total_reviews'] : 0;

        update_option('io_reviews_myplaceID', $placeId);
        update_option('io_reviews_google_avg_rating', $rating);
        update_option('io_reviews_google_total_reviews', $userRatingsTotal);
    }

    private function apply_filters()
    {
        $this->update_rating_filter();
        $this->update_time_filter();
        $this->store_filtered_ids();
    }

    private function update_rating_filter()
    {
        $ratingFilter = isset($_POST['filter_rating']) ? (int)$_POST['filter_rating'] : 0;
        update_option('io_reviews_iotestimonials_star_filterlevel', $ratingFilter);
        update_option('io_reviews_google_star_filterlevel', $ratingFilter);
    }

    private function update_time_filter()
    {
        $timeFilter = isset($_POST['filter_time']) ? $_POST['filter_time'] : 'all';
        update_option('io_reviews_iotestimonials_time_filter', $timeFilter);
        update_option('io_reviews_google_time_filter', $timeFilter);
    }

    private function store_filtered_ids()
    {
        $this->store_filtered_testimonials_ids();
        $this->store_filtered_google_reviews_ids();
    }

    private function store_filtered_testimonials_ids()
    {
        $reviewsIotestimonialsData = $this->get_filtered_iotestimonials_data();
        $filteredTestimonialsIds = array_column($reviewsIotestimonialsData, 'testimonial_id');
        update_option('io_reviews_iotestimonials_star_filterIDs', $filteredTestimonialsIds);
    }

    private function store_filtered_google_reviews_ids()
    {
        $reviewsGoogleData = $this->get_filtered_google_reviews_data();
        $filteredGoogleReviewIds = array_column($reviewsGoogleData, 'time');
        update_option('io_reviews_google_star_filterIDs', $filteredGoogleReviewIds);
    }

    public function check_reviews()
    {
        // Get the site's host
        $site_url = parse_url(get_site_url(), PHP_URL_HOST);

        // Normalize the site URL
        $normalized_site_url = strtolower($site_url);
        $normalized_site_url = preg_replace('/^www\./', '', $normalized_site_url);
        $normalized_site_url = rtrim($normalized_site_url, '/');

        // Compare the normalized URLs
        if (get_option('io_gmb_access'))
            $this->fetch_reviews_using_gmb_api($normalized_site_url);
        else
            $this->fetch_reviews_using_places_api();

        // After fetching reviews, check and convert ratings if necessary
        $this->convert_and_resave_google_reviews();

        //adding this here so the hourly automation runs it
        $this->retrieve_place_id_for_SEO_clients();
    }

    private function convert_and_resave_google_reviews()
    {
        $reviewsGoogle = get_option('io_reviews_google');
        if (!$reviewsGoogle) {
            return;
        }

        $reviewsGoogleData = json_decode($reviewsGoogle, true);

        $needsUpdate = false;

        foreach ($reviewsGoogleData as &$review)
        {
            if (!is_numeric($review['rating']))
            {
                $numericRating = $this->convert_word_rating_to_number($review['rating']);
                if ($numericRating !== 0)
                {
                    $review['rating'] = $numericRating;
                    $needsUpdate = true;
                }
            }
        }

        if ($needsUpdate) update_option('io_reviews_google', json_encode($reviewsGoogleData));

    }

    private function fetch_reviews_using_gmb_api($businessUrl)
    {
        // Initialize Google Client
        $client = $this->initialize_google_client();

        // Get accounts
        $account_service = new Google\Service\MyBusinessAccountManagement($client);
        $accounts = $account_service->accounts->listAccounts();

        // Initialize location service
        $location_service = new Google\Service\MyBusinessBusinessInformation($client);

        $reviewsFetched = false;

        $locations = $location_service->accounts_locations->listAccountsLocations($accounts[0]->name, ['readMask' => 'title,name,websiteUri', 'pageSize' => '100']);

    if (isset($locations->locations) && is_array($locations->locations))
    {
        foreach ($locations->locations as $locationData)
        {
            // Sanitize this location's URL
            $current_location_url = $locationData->websiteUri;
            $current_location_url = preg_replace('#^https?://#i', '', $current_location_url);
            $current_location_url = preg_replace('#^www\.#i', '', $current_location_url);

            // Strip query parameters for comparison
            $current_location_base = preg_replace('/\?.*$/', '', $current_location_url);
            $current_location_base = rtrim($current_location_base, '/');

            // Sanitize business URL parameter
            $sanitizedBusinessUrl = preg_replace('#^https?://#i', '', $businessUrl);
            $sanitizedBusinessUrl = preg_replace('#^www\.#i', '', $sanitizedBusinessUrl);
            $sanitizedBusinessUrl = preg_replace('/\?.*$/', '', $sanitizedBusinessUrl);
            $sanitizedBusinessUrl = rtrim($sanitizedBusinessUrl, '/');

            // Check for a match between the parameter URL and the current location's website URI
            if ($sanitizedBusinessUrl == $current_location_base)
            {
                // Retrieve reviews using curl
                $accessTokenArray = $client->getAccessToken();
                if (isset($accessTokenArray['access_token'])) {
                    $accessToken = $accessTokenArray['access_token'];
                } else {
                    return;
                }

                $reviewsArray = [];
                $pageToken = null;

                    do
                    {
                        $api_url = 'https://mybusiness.googleapis.com/v4/'. $accounts[0]->name . '/' . $locationData->name . '/reviews';
                    // Add query parameters
                    $query_params = [
                        'pageSize' => 50, // Maximum page size
                    ];
                    if ($pageToken) {
                        $query_params['pageToken'] = $pageToken;
                    }
                    $api_url .= '?' . http_build_query($query_params);

                    // Make the curl call
                    $ch = curl_init();
                    curl_setopt($ch, CURLOPT_URL, $api_url);
                    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                        'Authorization: Bearer ' . $accessToken,
                        'Content-Type: application/json',
                    ));
                    $response = curl_exec($ch);
                    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                    curl_close($ch);

                        if ($http_code == 200)
                        {
                            $response_data = json_decode($response, true);
                            if (isset($response_data['reviews']) && is_array($response_data['reviews']))
                            {
                            // Process the reviews
                                foreach ($response_data['reviews'] as $review)
                                {
                                    $numericRating = $this->convert_word_rating_to_number($review['starRating']);

                                    $reviewsArray[] = [
                                        'author_name' => $review['reviewer']['displayName'] ?? 'Anonymous',
                                        'rating' => $numericRating,
                                        'text' => $review['comment'] ?? '',
                                        'time' => strtotime($review['createTime']),
                                        'profile_photo_url' => $review['reviewer']['profilePhotoUrl'] ?? (isset($review['reviewer']['profilePhotoUrl']) ? $review['reviewer']['profilePhotoUrl'] : ''),
                                    ];
                            }
                        }

                        // Check if there's a nextPageToken for pagination
                            if (isset($response_data['nextPageToken']))
                            {
                                $pageToken = $response_data['nextPageToken'];
                            }
                            else
                            {
                                $pageToken = null;
                            }
                        }
                        else
                        {
                            break;
                        }

                } while ($pageToken);

                    if (!empty($reviewsArray))
                    {
                        // Save reviews in options (encode as JSON)
                        update_option('io_reviews_google', json_encode($reviewsArray));
                        $reviewsFetched = true;
                        break; // Exit the foreach loop once reviews are fetched
                    }
                }
            }
        }
    }

	private function convert_word_rating_to_number($wordRating)
	{
	// Map word ratings to their corresponding numeric values
		$ratingMap =
		[
			'ONE' => 1,
			'TWO' => 2,
			'THREE' => 3,
			'FOUR' => 4,
			'FIVE' => 5,
		];

	// Return the numeric rating if it exists in the map, otherwise return 0
		return isset($ratingMap[strtoupper($wordRating)]) ? $ratingMap[strtoupper($wordRating)] : 0;
	}

    private function initialize_google_client()
    {
        $token_data = json_decode(get_option('io_gmb_access'), true);

    // Initialize Google Client
        $json_credentials_path = __DIR__ . '/../includes/GMB/GMB_Client_Credentials.json';
        $client = new Google_Client();
        $client->setAuthConfig($json_credentials_path);
        $client->setScopes('https://www.googleapis.com/auth/business.manage');
        $client->setAccessType('offline');

        if ($token_data)
        {
            $client->setAccessToken($token_data);

            if ($client->isAccessTokenExpired())
            {
                if ($client->getRefreshToken())
                {
                    $newTokenData = $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
                    update_option('io_gmb_access', json_encode($newTokenData));
                }
                else
                {
                    echo "Access token has expired and cannot be refreshed.";
                }
            }
        }
        else
        {
            echo "No access token available. Please authenticate.";
        }
        return $client;
    }
#endregion

    public function fetch_reviews_using_places_api()
    {
        $myplaceID = get_option('io_reviews_myplaceID');
        if (!$myplaceID) return;

        $apiKey = 'AIzaSyD_dnIIQ-VJRWlogZCEHauI24Nvuix-SiE';
        $fields = 'reviews,rating,user_ratings_total';
        $url = "https://maps.googleapis.com/maps/api/place/details/json?place_id={$myplaceID}&fields={$fields}&key={$apiKey}";

        $response = $this->make_api_call($url);
        $detailsArray = json_decode($response, true);

        if (isset($detailsArray['result']))
        {
            $result = $detailsArray['result'];

        // Update overall average rating and total reviews count directly
            $avgRating = isset($result['rating']) ? (float)$result['rating'] : 0;
            $totalReviews = isset($result['user_ratings_total']) ? (int)$result['user_ratings_total'] : 0;

            update_option('io_reviews_google_avg_rating', $avgRating);
            update_option('io_reviews_google_total_reviews', $totalReviews);

        // Logic to handle individual reviews
            if (isset($result['reviews']))
            {
                $fetchedReviews = $result['reviews'];
                $fetchedReviews = array_filter($fetchedReviews, function ($review)
                {
                    return !in_array($review['time'], get_option('io_reviews_google_exclude', []));
                });

            // Ensure ratings are numeric
                foreach ($fetchedReviews as &$review)
                {
                    if (!is_numeric($review['rating']))
                    {
                        $review['rating'] = $this->convert_word_rating_to_number($review['rating']);
                    }
                }

                update_option('io_reviews_google', json_encode($fetchedReviews));
            }
        }
    }

    private function search_business()
    {
        $businessName = urlencode($_POST['business_name']);
        $apiKey = 'AIzaSyD_dnIIQ-VJRWlogZCEHauI24Nvuix-SiE';
        $fields = 'place_id,name,rating,user_ratings_total,formatted_address';
        $url = "https://maps.googleapis.com/maps/api/place/findplacefromtext/json?input={$businessName}&fields={$fields}&inputtype=textquery&key={$apiKey}";

        $response = $this->make_api_call($url);

        $responseArray = json_decode($response, true);

        if (isset($responseArray['candidates']) && is_array($responseArray['candidates']))
        {
            $this->candidates = $responseArray['candidates'];
            $_POST['active_tab'] = 'google-reviews';
        }
        else
        {
            echo '<div class="alert alert-warning" role="alert">No results found.</div>';
        }
    }

    private function get_place_details($placeId)
    {
        $apiKey = 'AIzaSyD_dnIIQ-VJRWlogZCEHauI24Nvuix-SiE';
        $fields = 'name,formatted_address,rating,user_ratings_total';
        $url = "https://maps.googleapis.com/maps/api/place/details/json?place_id={$placeId}&fields={$fields}&key={$apiKey}";

        $response = $this->make_api_call($url);
        $detailsArray = json_decode($response, true);

        return $detailsArray['result'];
    }

    private function make_api_call($url)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        $response = curl_exec($ch);
        curl_close($ch);

        return $response;
    }

    public function render_page()
    {
        $myplaceID = get_option('io_reviews_myplaceID') ? get_option('io_reviews_myplaceID') : get_option('io_gmb_auth');
        $googleTabActive = isset($_POST['active_tab']) && $_POST['active_tab'] === 'google-reviews';

        $reviewsGoogleData = $this->get_filtered_google_reviews_data();
        $reviewsIotestimonialsData = $this->get_filtered_iotestimonials_data();

        // Ensure all variables are defined before passing to the view
        $ratingFilter = get_option('io_reviews_iotestimonials_star_filterlevel', 0);
        $filteredTestimonialsIds = get_option('io_reviews_iotestimonials_star_filterIDs', []);
        $timeFilter = get_option('io_reviews_iotestimonials_time_filter', 'all');
        $filteredTimeTestimonialsIds = get_option('io_reviews_iotestimonials_time_filterIDs', []);
        $googleRatingFilter = get_option('io_reviews_google_star_filterlevel', 0);
        $filteredGoogleReviewIds = get_option('io_reviews_google_star_filterIDs', []);
        $googleTimeFilter = get_option('io_reviews_google_time_filter', 'all');
        $filteredTimeGoogleReviewIds = get_option('io_reviews_google_time_filterIDs', []);

        require_once(__DIR__ . '/adminPageView.php');
    }

    private function get_filtered_google_reviews_data()
    {
        $reviewsGoogle = get_option('io_reviews_google');
        $filteredGoogleReviewIds = get_option('io_reviews_google_star_filterIDs', []);
        $filteredTimeGoogleReviewIds = get_option('io_reviews_google_time_filterIDs', []);
        $googleRatingFilter = get_option('io_reviews_google_star_filterlevel', 0);
        $googleTimeFilter = get_option('io_reviews_google_time_filter', 'all');

        $reviewsGoogleData = $reviewsGoogle ? json_decode($reviewsGoogle, true) : [];

        // Ensure ratings are numeric
        foreach ($reviewsGoogleData as &$review)
        {
            if (!is_numeric($review['rating']))
            {
                $review['rating'] = $this->convert_word_rating_to_number($review['rating']);
            }
        }

        $timeFilterTimestamp = $this->get_time_filter_timestamp($googleTimeFilter);

        $filteredGoogleData = array_filter($reviewsGoogleData, function ($review) use ($googleRatingFilter, $timeFilterTimestamp)
        {
            return $review['rating'] >= $googleRatingFilter &&
                   $review['time'] >= $timeFilterTimestamp;
        });

        return $filteredGoogleData;
    }

    private function get_filtered_iotestimonials_data()
    {
        $reviewsIotestimonials = get_option('io_reviews_iotestimonials');
        $filteredTestimonialsIds = get_option('io_reviews_iotestimonials_star_filterIDs', []);
        $filteredTimeTestimonialsIds = get_option('io_reviews_iotestimonials_time_filterIDs', []);
        $ratingFilter = get_option('io_reviews_iotestimonials_star_filterlevel', 0);
        $timeFilter = get_option('io_reviews_iotestimonials_time_filter', 'all');

        $reviewsIotestimonialsData = $reviewsIotestimonials ? json_decode($reviewsIotestimonials, true) : [];

        $timeFilterTimestamp = $this->get_time_filter_timestamp($timeFilter);

        $filteredIotestimonialsData = array_filter($reviewsIotestimonialsData, function ($review) use ($ratingFilter, $timeFilterTimestamp)
        {
            return $review['testimonial_rating'] >= $ratingFilter &&
                   $review['testimonial_time'] >= $timeFilterTimestamp;
        });

        return $filteredIotestimonialsData;
    }

    private function get_time_filter_timestamp($timeFilter)
    {
        $timeFilterTimestamps = [
            '6_months' => strtotime('-6 months'),
            '1_year' => strtotime('-1 year'),
            '3_years' => strtotime('-3 years'),
            'all' => 0
        ];

        return $timeFilterTimestamps[$timeFilter];
    }

    private function update_widget_type()
    {
        update_option('io_reviews_widget_type', $_POST['review_type']);
    }

    private function retrieve_place_id_for_SEO_clients()
    {
    // only run for sites that have GMB access data
        $raw = get_option('io_gmb_access');
        if (empty($raw)) return;

        $token_data = json_decode(get_option('io_gmb_access'), true);

        $json_credentials_path = plugin_dir_path(__FILE__) . '/../includes/GMB/GMB_Client_Credentials.json';
        $client = new Google_Client();
        $client->setAuthConfig($json_credentials_path);
        $client->setScopes('https://www.googleapis.com/auth/business.manage');
        $client->setAccessType('offline');

        $token_expiration_time = $token_data["created"] + $token_data["expires_in"];
        $token_is_expired = false;

        if (time() > $token_expiration_time && $token_expiration_time > 0)
        {
            $token_is_expired = true;
            $refreshed_token_data = $client->fetchAccessTokenWithRefreshToken($token_data["refresh_token"]);
            update_option('io_gmb_access', json_encode($refreshed_token_data));
        }

        if ($token_is_expired)
        {
            if (is_array($refreshed_token_data) && isset($refreshed_token_data[0]))
            {
                $refreshed_token_data = $refreshed_token_data[0];
            }
            $client->setAccessToken($refreshed_token_data['access_token']);
        }
        else
        {
            if (is_array($token_data) && isset($token_data[0]))
            {
                $token_data = $token_data[0];
            }
            $client->setAccessToken($token_data["access_token"]);
        }

        $account_service  = new Google\Service\MyBusinessAccountManagement($client);
        $location_service = new Google\Service\MyBusinessBusinessInformation($client);
        $accounts         = $account_service->accounts->listAccounts();

    //url + path(or subdirectory) parsing
        $siteParsed = parse_url(get_site_url());
        $siteDomain = !empty($siteParsed['host']) ? strtolower(preg_replace('/^www\./i', '', $siteParsed['host'])) : '';
        $sitePath   = !empty($siteParsed['path']) ? rtrim($siteParsed['path'], '/') : '';
        $siteCompareValue = $siteDomain . $sitePath;

    // Return placeId or null if not found
        $placeIdResult = null;

        foreach ($accounts as $account)
        {
            $locationsResponse = $location_service->accounts_locations->listAccountsLocations(
                $account->name,
                [
                    'readMask' => 'name,websiteUri,metadata.placeId',
                    'pageSize' => 100
                ]
            );

            if (!isset($locationsResponse->locations) || !is_array($locationsResponse->locations))
            {
                continue;
            }

            foreach ($locationsResponse->locations as $locationData)
            {
            //matching on current site's domain+path
                $locUriParsed = parse_url($locationData->websiteUri ?? '');
                $locDomain    = !empty($locUriParsed['host']) ? strtolower(preg_replace('/^www\./i', '', $locUriParsed['host'])) : '';
                $locPath      = !empty($locUriParsed['path']) ? rtrim($locUriParsed['path'], '/') : '';
                $locCompareValue = $locDomain . $locPath;

                if ($locCompareValue === $siteCompareValue)
                {
                    $placeIdResult = $locationData->metadata->placeId ?? null;
                    break 2; // Stop once found
                }
            }
        }

        if($placeIdResult !== null)
        {
            update_option('io_reviews_myplaceID', $placeIdResult);
            update_option('io_gmb_place_id_not_found', '0');
        }
        else
        {
            update_option('io_gmb_place_id_not_found', '1');
        }
        //echo $placeIdResult;
        //return $placeIdResult; // This will be the placeId or null
    }




}
?>