<?php
/**
 * FluentC WordPress Connect File.
 *
 * This file contains the functions for managing connect to FluentC Services
 *
 * @category Translation
 * @package  FluentCPlugin
 * @author   FluentC <wp@fluentc.io>
 * @license  http://www.gnu.org/copyleft/gpl.html GNU General Public License
 * @link     https://www.fluentc.ai
 */

namespace FluentC\Services;

use FluentC\Models\Body;


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

/**
 * FluentC Connection Class
 */
class Connect
{
    /**
     * Summary of fluentc_cache
     * @var 
     */
    protected $fluentc_cache;
    /**
     * Summary of fluentc_remote_url
     * @var 
     */
    protected $fluentc_remote_url;
    /**
     * Summary of api_key
     * @var string
     */
    protected $api_key = 'da2-wtkl5bpofjbu5ex5iugu4o2mbm';
    /**
     * Summary of __construct
     */
    public function __construct()
    {
        $this->fluentc_cache = new Cache();
        $this->fluentc_remote_url = 'https://dashboard.fluentc.ai/graphql';
    }
    /**
     * Summary of get_language_list
     * @param mixed $widget_id
     * @return mixed
     */
    public function get_language_list($widget_id)
    {
        return $this->getCachedOrFetch('fluentc_language_list', function () use ($widget_id) {
            $languages = [];
            $get_all_languages = $this->get_available_languages($widget_id);
            foreach ($get_all_languages->data->getAvailableLanguages->body as $value) {
                $languages[] = $value->code;
            }
            do_action('fluentc_activation_setup');
            return $languages;
        }, 43200);
    }
    /**
     * Summary of get_display_language_list
     * @param mixed $widget_id
     * @return mixed
     */
    public function get_display_language_list($widget_id)
    {
        return $this->getCachedOrFetch('fluentc_display_language_list', function () use ($widget_id) {
            $languages = [];
            $get_all_languages = $this->get_available_languages($widget_id);
            foreach ($get_all_languages->data->getAvailableLanguages->body as $value) {
                $languages[] = [$value->name, $value->code];
            }
            do_action('fluentc_activation_setup');
            return $languages;
        }, 43200);
    }

  /**
 * Retrieves FluentC Languages as an array.
 *
 * This function fetches the available languages from FluentC, caches them,
 * and applies any filtering based on the provided arguments.
 *
 * @param array $args Optional. Arguments to filter the languages.
 *                    Supported args:
 *                    - 'hide_empty' (bool) Whether to hide languages with no posts.
 *                    - 'hide_default' (bool) Whether to hide the default language.
 *                    - 'fields' (string|array) Specific fields to return.
 * @return array|null An array of language objects, or null if no API key is set.
 */
public function get_fluentc_languages_list($args = [])
{
    $widgetapikey = get_option('fluentc_api_key');
    if (!$widgetapikey) {
        return null;
    }

    return $this->getCachedOrFetch('fluentc_array_language_list', function () use ($widgetapikey, $args) {
        $get_all_languages = $this->get_available_languages($widgetapikey);
        $languages = array_map(function ($language) {
            return (object) [
                'name' => $language->name,
                'slug' => $language->code,
                'is_default' => false,
                'count' => 0,
            ];
        }, $get_all_languages->data->getAvailableLanguages->body);

        return $this->filterLanguages($languages, $args);
    }, 43200);
}

/**
 * Filters the languages based on provided arguments.
 *
 * @param array $languages Array of language objects to filter.
 * @param array $args Arguments for filtering. See get_fluentc_languages_list() for details.
 * @return array Filtered array of language objects.
 */
	private function filterLanguages($languages, $args)
    {
        $languages = array_filter($languages, function ($language) use ($args) {
            $keep_empty = empty($args['hide_empty']) || $language->count;
            $keep_default = empty($args['hide_default']) || !$language->is_default;
            return $keep_empty && $keep_default;
        });

        $languages = array_values($languages);

        return empty($args['fields']) ? $languages : wp_list_pluck($languages, $args['fields']);
    }
    /**
     * Summary of fetch_widget_options
     * @param mixed $widget_id
     * @return mixed
     */
    public function fetch_widget_options($widget_id)
    {
        return $this->getCachedOrFetch($widget_id, function () use ($widget_id) {
            return $this->makeGraphQLRequest(
                "{\n  fetchSiteOptions(\n   siteId: \"$widget_id\"\n   ) {\n    disabled\n    name\n    appearance\n   sourceLanguage\n  languages\n      }\n}"
            );
        }, 43200);
    }
    /**
     * Summary of get_available_languages
     * @param mixed $environment_id
     * @return mixed
     */
    public function get_available_languages($environment_id)
    {
        return $this->makeGraphQLRequest(
            "{\n  getAvailableLanguages(\n    siteId: \"$environment_id\"\n  targetLanguage:\"en\"\n ) {\n  body\n {\n name\n code\n }}\n}"
        );
    }
    
    /**
     * Summary of get_translation_text
     * @param mixed $widget_id
     * @param mixed $urls_array
     * @return mixed
     */
    public function send_translate_urls($widget_id, $urls_array)
    {
        $query = $this->buildTranslateUrls($widget_id, $urls_array);
        
        do_action('qm/debug', 'GraphQL Query: ' . $query);

        $response = $this->makeGraphQLRequest($query);
        if (!$response) {
            do_action('qm/error', 'Translate URL error: No response from API');
            return;
        }

        if (!isset($response->data->translateUrls->jobId)) {
            do_action('qm/error', 'Translation error: Unexpected response structure');
            do_action('qm/debug', 'API Response: ' . json_encode($response));
            return;
        }
        $this->fluentc_cache->set('fluentc_batch_request', $response->data->translateUrls->jobId, 'urls', 300);
        return $response->data->translateUrls->jobId;
    }

    public function get_latest_batch_status($site_id)
    {
        $query = $this->fetch_latest_batch_status($site_id);
        $response = $this->makeGraphQLRequest($query);

        if (isset($response->data->latestBatchStatus)) {
            return $response->data->latestBatchStatus;
        }

        return null;
    }
    /**
     * Fetch job status
     * @param mixed $job_id
     * @return mixed
     */
    public function fetch_job_status($job_id)
    {
        $query = $this->fetch_batch_job_status($job_id);
        
        do_action('qm/debug', 'GraphQL Query: ' . $query);

        $response = $this->makeGraphQLRequest($query);
        if (!$response) {
            do_action('qm/error', 'BatchJob error: No response from API');
            return;
        }

        if (!isset($response->data->batchTranslationProgress->jobId)) {
            do_action('qm/error', 'Translation error: Unexpected response structure');
            do_action('qm/debug', 'API Response: ' . json_encode($response));
          return;
        }
       
        $this->fluentc_cache->set('fluentc_batch_request', $response->data->batchTranslationProgress, 'temp', 100);
        return $response->data->batchTranslationProgress;
    }


    public function get_translation_content_html($widget_id, $source_language, $target_language, $html, $path = '')
    {
        
        $query = $this->buildTranslateHtmlQuery($widget_id, $html,$source_language, $target_language, true, $path);
      
        do_action('qm/debug', 'GraphQL Query: ' . $query);

        $response = $this->makeGraphQLRequest($query);
       
        $this->fluentc_cache->set('apicalls', $this->fluentc_cache->get('apicalls', 'settings') + 1, 'setting', 720);
        if (!$response) {
            do_action('qm/error', 'Translation error: No response from API');
            return '';
        }

        if (!isset($response->data->translateHtml->body)) {
            do_action('qm/error', 'Translation error: Unexpected response structure');
            do_action('qm/debug', 'API Response: ' . json_encode($response));
            return '';
        }

         // Ensure we're returning a string
    if (is_string($response->data->translateHtml->body)) {
        return $response->data->translateHtml->body;
    } else {
        do_action('qm/error', 'Translation error: Response body is not a string');
        do_action('qm/debug', 'Body type: ' . gettype($response->data->translateHtml->body));
        
        // Convert to string if possible, otherwise return empty string
        if (is_scalar($response->data->translateHtml->body)) {
            return (string)$response->data->translateHtml->body;
        } else {
            return '';
        }
    }
    }
   

     /**
     * Summary of buildTranslationQuery
     * @param mixed $widget_id
     * @param mixed $urls_string
     * @return string
     */
    private function buildTranslateUrls($widget_id, $urls_array)
    {

        $urls_json = json_encode($urls_array, JSON_UNESCAPED_UNICODE);
        return <<<GRAPHQL
        {
          translateUrls(
            siteId: "$widget_id"
          ) {
             jobId 
          }
        }
        GRAPHQL;
    }
  /**
     * Summary of fetch_job_status
     * @param mixed $widget_id
     * @param mixed $urls_string
     * @return string
     */
    private function fetch_batch_job_status($job_id)
    {

       
        return <<<GRAPHQL
        {
          batchTranslationProgress(
            jobId: "$job_id"
          ) {
            jobId
            status
            totalSteps
            completedSteps
            createdAt
          }
        }
        GRAPHQL;
    }
  /**
     * Summary of fetch_job_status
     * @param mixed $widget_id
     * @param mixed $urls_string
     * @return string
     */
    private function fetch_latest_batch_status($site_id)
    {

       
        return <<<GRAPHQL
        {
          latestBatchStatus(
            siteId: "$site_id"
          ) {
            createdAt
            completedUrls
            completionPercentage
            batchId
            status
          }
        }
        GRAPHQL;
    }
    
    

    /**
     * Summary of buildTranslateHtmlQuery
     * @param mixed $widget_id
     * @param mixed $html
     * @param mixed $source_language
     * @param mixed $target_language
     * @param mixed $base64
     * @param mixed $path
     * @return string
     */
    private function buildTranslateHtmlQuery($widget_id, $html, $source_language, $target_language, $base64 = true, $path = '')
{
    // Base64 encode the HTML content
    
    // Build the path parameter if provided
    $path_param = !empty($path) ? "path: \"$path\"" : '';
    
    return <<<GRAPHQL
    {
      translateHtml(
        siteId: "$widget_id"
        html: "$html"
        sourceLanguage: "$source_language"
        targetLanguage: "$target_language"
        base64Encode: true
        $path_param
      ) {
        body
      }
    }
    GRAPHQL;
}
    
    /**
 * Sends a heartbeat to the FluentC API
 *
 * @param string|null $widget_id The FluentC API key (can be null)
 * @return mixed The API response or null on error
 */
public function heartbeat($widget_id = null)
{
    $site_url = $this->getSiteUrl();
    // Include site ID in query only if we have an API key
    $site_detail = $widget_id ? 'siteId: "' . $widget_id . '", ' : '';
    
    // Get API call count, default to 0 if not set
    $apicalls = $this->fluentc_cache->get('apicalls', 'settings');
    if ($apicalls === false) {
        $apicalls = 0;
    }
    
    $query = <<<GRAPHQL
    {
      heartBeat(
        host: "$site_url",
        $site_detail
        apiCalls:$apicalls, 
        action:"heartbeat"
      ) {
        body {
          status
        }
      }
    }
    GRAPHQL;

    // Pass false to indicate this request doesn't require an API key
    $response = $this->makeGraphQLRequest($query, false);

    if ($response && isset($response->data)) {
        do_action('qm/info', 'FluentC Site setup post completed');
        return $response;
    }

    return null;
}
    /**
     * Summary of getSiteUrl
     * @return string
     */
    private function getSiteUrl()
    {
        $site_language = get_bloginfo('url');
        $url_parts = wp_parse_url($site_language);
        return $url_parts['scheme'] . '://' . $url_parts['host'];
    }

	/**
	 * Summary of getCachedOrFetch
	 * @param mixed $key
	 * @param mixed $fetchCallback
	 * @param mixed $expiration
	 * @return mixed
	 */
    private function getCachedOrFetch($key, $fetchCallback, $expiration = 720)
{
    $cached = $this->fluentc_cache->get($key,'settings');
    if ($cached !== false) {
        return is_string($cached) ? json_decode($cached) : $cached;
    }

    $data = $fetchCallback();
    if ($data !== null) {
       $this->fluentc_cache->set($key, is_string($data) ? $data : json_encode($data), 'settings', $expiration);
    }

    return $data;
}
/**
 * Summary of get_pll_fluentc_languages_list
 * @param mixed $args
 * @return array
 */
public function get_pll_fluentc_languages_list($args = [])
{
    $widgetapikey = get_option('fluentc_api_key');
    if (!$widgetapikey) {
        return []; // Return an empty array instead of null
    }

    return $this->getPLLCachedOrFetch('fluentc_array_language_list', function () use ($widgetapikey, $args) {
        $get_all_languages = $this->get_available_languages($widgetapikey);
        
        // Check if the API call was successful
        if (!$get_all_languages || !isset($get_all_languages->data->getAvailableLanguages->body)) {
            return []; // Return an empty array if there's an error
        }
        
        $languages = array_map(function ($language) {
            return (object) [
                'name' => $language->name,
                'slug' => $language->code,
                'is_default' => false,
                'count' => 0,
            ];
        }, $get_all_languages->data->getAvailableLanguages->body);

        return $this->filterLanguages($languages, $args);
    }, 43200);
}

/**
 * Summary of getPLLCachedOrFetch
 * @param mixed $key
 * @param mixed $fetchCallback
 * @param mixed $expiration
 * @return array
 */
private function getPLLCachedOrFetch($key, $fetchCallback, $expiration = 720)
{
    $cached = $this->fluentc_cache->get($key,'settings');
    if ($cached !== false) {
        // Ensure we always return an array
        $decoded = is_string($cached) ? json_decode($cached, true) : $cached;
        return is_array($decoded) ? $decoded : [];
    }

    $data = $fetchCallback();
    if ($data !== null) {
        $this->fluentc_cache->set($key, is_string($data) ? $data : json_encode($data), 'settings', $expiration);
    }

    // Ensure we always return an array
    return is_array($data) ? $data : [];
}
    /**
     * Summary of makeGraphQLRequest
     * @param mixed $query
     * @return mixed
     */
    private function makeGraphQLRequest($query, $require_api_key = true)
    {
        // Only check for API key if this request requires one
        if ($require_api_key) {
            $widgetapikey = get_option('fluentc_api_key');
            if (empty($widgetapikey)) {
                return null;
            }
        }
        $response = wp_remote_post($this->fluentc_remote_url, [
            'body' => wp_json_encode(['query' => $query]),
            'headers' => [
                'Content-Type' => 'application/json',
                'x-api-key' => $this->api_key,
            ],
            'timeout' => 20,
        ]);

        if (is_wp_error($response)) {
            do_action('qm/error', 'Error in request: ' . $response->get_error_message());
            return null;
        }

        $body = wp_remote_retrieve_body($response);
        $status = wp_remote_retrieve_response_code($response);

        $response_data = json_decode($body);

        if ($status !== 200 || !$response_data) {
            $this->handleRequestError($status, $response_data);
            return null;
        }

        return $response_data;
    }

    /**
     * Summary of handleRequestError
     * @param mixed $status
     * @param mixed $response_data
     * @return void
     */
    private function handleRequestError($status, $response_data)
    {
        if ($status !== 200) {
            do_action('qm/error', "HTTP Error: $status");
        }

        if (!$response_data) {
            do_action('qm/error', 'Invalid JSON response');
            return;
        }

        if (isset($response_data->errors)) {
            foreach ($response_data->errors as $error) {
                $code = $error->extensions->code ?? 'UNKNOWN_ERROR';
                $message = $error->message ?? 'An unknown error occurred';
                do_action('qm/error', "GraphQL Error ($code): $message");
            }
        }
    }
    public function get_language_list_string($widget_id)
    {
        $languages = $this->get_language_list($widget_id);
        return empty($languages) ? '' : implode('|', $languages);
    }
}
