<?php
namespace SPAATG\Controller\Api;

use SPAATG\ShortPixelLogger\ShortPixelLogger as Log;
use SPAATG\Controller\ApiKeyController as ApiKeyController;

use SPAATG\Controller\Queue\QueueItems as QueueItems;
use \SPAATG\Model\Queue\QueueItem as QueueItem;
use SPAATG\Model\Image\ImageModel as ImageModel;


if ( ! defined( 'ABSPATH' ) ) {
 exit; // Exit if accessed directly.
}


class AiController extends RequestManager
{

    protected $main_url;
    protected $auth_token = 'spaatg_ai_jwt_token';

    const AI_STATUS_INVALID_URL = 2;
    const AI_STATUS_OVERQUOTA = 3;


    public function __construct()
    {
     $this->main_url = 'https://capi-gpt.shortpixel.com/';
    }

    protected function getPricingUrl()
    {
      $keyControl = ApiKeyController::getInstance();
      $apiKey = $keyControl->forceGetApiKey();
      $path = ($apiKey) ? 'login/' . rawurlencode($apiKey) . '/pricing' : 'pricing';

      return esc_url('https://shortpixel.com/' . $path);
    }

    protected function maybeAddPricingLink($message)
    {
      if (! is_string($message) || strpos($message, 'href=') !== false)
      {
        return $message;
      }

      $matchesFeatureError =
        stripos($message, 'does not include the ai feature') !== false ||
        stripos($message, 'upgrade to the unlimited ai plan') !== false;

      if (! $matchesFeatureError)
      {
        return $message;
      }

      return sprintf(
        '%1$s <a href="%2$s" target="_blank">%3$s</a>.',
        $message,
        $this->getPricingUrl(),
        esc_html__('See pricing and upgrade options', 'shortpixel-ai-alt-text-generator')
      );
    }

    public function processMediaItem(QueueItem $qItem)
    {
      $imageObj = $qItem->imageModel;

      if (! is_object($imageObj))
      {
        $qItem->addResult($this->returnFailure(self::STATUS_FAIL, __('Item seems invalid, removed or corrupted.', 'shortpixel-ai-alt-text-generator')));
        return;
      }

      $keyControl = ApiKeyController::getInstance();

      //$request = $this->getRequest($requestArgs);
      $requestBody = [
        'plugin_version' => SPAATG_IMAGE_OPTIMISER_VERSION,
        'source' => 1,
      ];

      if ($qItem->data()->action == 'requestAlt')
      {
        $requestBody['url'] = $qItem->data()->urls[0];
        $paramlist = $qItem->data()->paramlist;
        if (is_object($paramlist))
        {
          $paramlist = (array) $paramlist;
        }
        if (! is_array($paramlist)) // not serious paramlist then
        {
           $paramlist = [];
        }

        $requestBody = array_merge($requestBody, $paramlist);
        $requestBody['retry'] = '1'; // when requesting alt, always wants a new one (?)
        $requestBody['version'] = 'v_2';
      }

      if ($qItem->data()->action == 'retrieveAlt')
      {
        $requestBody['id'] = $qItem->data()->remote_id;
      }


      $token = get_transient($this->auth_token);
      // Token doesn't seem to work normally.
      /*if ($token !== false)
      {
         $auth = $token;
      }
      else
      { */
        $auth = 'ApiKey ' . $keyControl->forceGetApiKey();
     // }


      // Should always check the results
      $requestParameters = [
        'blocking' => true,
        'headers' => [
            'Authorization' => $auth,
            'Content-Type' => 'application/json',
        ]
      ];

      $request = $this->getRequest($requestBody, $requestParameters);
      $this->doRequest($qItem, $request);

    }

    // Should return something that's usefull to set as response on the item.
    protected function handleResponse(QueueItem $qItem, $response)
    {
       $apiData = $this->parseResponse($response);//get the actual response from API, its an array
       Log::addInfo('HAndle AI Response! ', $apiData);

        // List all the random crap that might return.
        $id = isset($apiData['id']) ? intval($apiData['id']) : false;
        $jwt = isset($apiData['jwt']) ? sanitize_text_field($apiData['jwt']) : false;
        $status = isset($apiData['status']) ? intval($apiData['status']) : false;

        $error = isset($apiData['error']) ? sanitize_text_field($apiData['error']) : false;
        $is_error = (false !== $error) ? true : false;

        if (false !== $jwt)
        {
          $authKey = get_transient($this->auth_token);
          if (false === $authKey || $jwt !== $authKey)
          {
             set_transient($this->auth_token, $jwt, HOUR_IN_SECONDS);
          }

        }

        // @todo This is probably not something that would happen, since repsonse is from the body. Implement here most error coming from the raw request and returnOk/returnFalse etc.

        //if (true === $qItem->result()->is_error && true === $qItem->result()->is_done )
       // {
              /*   So far nothing needed here, documenting what has been seen.
              401 - Unauthorized
              422 - Unprocessable
                */


        // API seems to return two different formats :
        // 1.  requestAlt : Object in data, with ID as only return.
        // 2.  retrieveAlt: Array with first item ( zero index )

        if (false === $apiData)
        {
            return $this->returnRetry(RequestManager::STATUS_CONNECTION_ERROR, __('AI Api returned without any data. ', 'shortpixel-ai-alt-text-generator')) ;
        }

        if ($qItem->data()->action == 'requestAlt')
        {
            if (false === $id && false === $is_error)
            {
               return $this->returnRetry(RequestManager::STATUS_WAITING, __('Response without result object', 'shortpixel-ai-alt-text-generator'));
            }


            if (false !== $id)
            {
              $remote_id = intval($id);
              $qItem->addResult(['remote_id' => $remote_id]);

              return $this->returnSuccess(['remote_id' => $remote_id], RequestManager::STATUS_SUCCESS, __('Request for image SEO data sent to ShortPixel AI', 'shortpixel-ai-alt-text-generator'));
            }
            elseif(self::AI_STATUS_OVERQUOTA === $status)
            {
	               /* translators: 1: opening contact link, 2: closing contact link. */
	               return $this->returnFailure(RequestManager::STATUS_ERROR, sprintf(esc_html__('Your AI quota for this month has been exceeded. We would love to hear your feedback — please share it with us %1$shere%2$s.', 'shortpixel-ai-alt-text-generator'), '<a href="https://shortpixel.com/contact" target="_blank">', '</a>'));
            }
            elseif(self::AI_STATUS_INVALID_URL === $status)
            {
                return $this->returnFailure(RequestManager::STATUS_FAIL, __('No URL or Invalid URL', 'shortpixel-ai-alt-text-generator'));
            }
            else
            {
               return $this->returnFailure(RequestManager::STATUS_ERROR, $this->maybeAddPricingLink($error));
            }

        }

        if ($qItem->data()->action == 'retrieveAlt')
        {
              $aiData = array_filter([
                 'filename' => isset($apiData['file_name']) ? sanitize_text_field($apiData['file_name']) : null,
                 'alt' => isset($apiData['alt']) ? sanitize_text_field($apiData['alt']) : null,
                 'caption' => isset($apiData['caption']) ? sanitize_text_field($apiData['caption']) : null,
                 'relevance' => isset($apiData['relevance']) ? sanitize_text_field($apiData['relevance']) : null,
                 'description' => isset($apiData['image_description']) ? sanitize_text_field($apiData['image_description']) : null,
                 'post_title' => isset($apiData['title']) ? sanitize_text_field($apiData['title']) : null,
              ]);

              // Switch known Statii
              switch ($status)
              {
                  case '-1':  // Error of some kind
                    $apiStatus = RequestManager::STATUS_FAIL;
                    return $this->returnFailure($apiStatus, $this->maybeAddPricingLink($error));
                  break;
                  case '0': // queued
                      if (false !== $is_error)
                      {
                         return $this->returnFailure(RequestManager::STATUS_FAIL, $this->maybeAddPricingLink($error));
                      }
                  case '1':

                     return $this->returnOk(RequestManager::STATUS_WAITING, __('Waiting for result', 'shortpixel-ai-alt-text-generator'));
                  break;
                  case '2':  // Success of some kind.
                  default:
                      $successData = $this->handleSuccess($aiData, $qItem);
                      return $successData;
                  break;

            }
        }
      return $this->returnFailure(0, 'No remote ID?');
    }

    /**
     * Undocumented function
     *
     * @param array $aiData
     * @param object $qItem
     * @return array Result array via requestManager
     */
    protected function handleSuccess($aiData, QueueItem $qItem)
    {
      if (false === is_null($qItem->data()->returndatalist))
      {
         $returndatalist = $qItem->data()->returndatalist;
         if (is_object($returndatalist))
         {
           $returndatalist = (array) $returndatalist;
         }

         foreach($returndatalist as $name => $data)
         {
            if (is_object($data)) // annoying conversion somehow by json decode from record
            {
               $data = (array) $data;
            }
            if (! isset($aiData[$name]) && isset($data['status']))
            {
                $aiData[$name]  = $data['status'];
            }
         }
      }

      return $this->returnSuccess(['aiData' => $aiData], RequestManager::STATUS_SUCCESS, __('Retrieved AI Image SEO data', 'shortpixel-ai-alt-text-generator')); ;
    }

    protected function doRequest(QueueItem $item, $requestParameters)
    {
        // For now
        if (false === property_exists($item->data, 'remote_id') || is_null($item->data()->remote_id))
        {
           $this->apiEndPoint = $this->main_url . 'add-url.php';
        }
        else {
          $this->apiEndPoint = $this->main_url . 'get-url.php';
        }

        return parent::doRequest($item, $requestParameters);

    }

    protected function returnFailure($code, $message)
    {
       if (401 == $code)
       {
          $token = get_transient($this->auth_token);
          if ($token !== false)
          {
             delete_transient($this->auth_token);
             return $this->returnRetry($code, __('Authentication token failure - Reset - Please wait', 'shortpixel-ai-alt-text-generator'));
          }
       }
       return parent::returnFailure($code, $message);
    }


}
