<?php
namespace ShortPixel\Helper;

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

use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;
use ShortPixel\Controller\ResponseController as ResponseController;

class DownloadHelper
{
		  private static $instance;

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

			public static function getInstance()
			{
				 if (is_null(self::$instance))
				 {
					  self::$instance = new DownloadHelper();
				 }

				 return self::$instance;
			}

			protected function checkEnv()
			{
				if ( ! function_exists( 'download_url' ) ) {
						require_once ABSPATH . 'wp-admin/includes/file.php';
				}
			}

			public function downloadFile($url, $args = array())
			{
					$defaults = array(
						'expectedSize' => null,
            'destinationPath' => null,
					);

					$args = wp_parse_args($args, $defaults);
          $success = false;

					Log::addDebug('Downloading file :' . $url, $args);

          $methods = array(
              "download_url" => array(array($this, 'downloadURLMethod'), $url, false),
              "download_url_force" => array(array($this, 'downloadURLMethod'), $url, true),
              "remote_get" => array(array($this, 'remoteGetMethod'), $url)
          );

          foreach($methods as $name => $data)
          {
             $function = $data[0];
             if (is_callable($function))
             {
                $result = call_user_func_array($function, array_slice($data, 1) );

                if (false !== $result)
                {
                   $tempFile = $result;
                   $success = true;
                   break;
                }
             }
          }

					if (false === $success)
					{
						Log::addError('Failed to download File', $result);
						ResponseController::addData('is_error', true);
						//Responsecontroller::addData('message', $tempFile->get_error_message());
						return false;
					}

					$fs = \wpSPIO()->filesystem();
					$file = $fs->getFile($tempFile);

          if (! is_null($args['destinationPath']))
          {
             $result = $this->moveDownload($file, $args['destinationPath']);
             if (false === $result)
             {
               Log::addError('Failed to move Download', $args);
               ResponseController::addData('is_error', true);
               Responsecontroller::addData('message', __('Failed to move download to destination!', 'shortpixel-image-optimiser'));
               return false;
             }
             else {
               $file = $result;
             }
          }

					return $file;
			}

      protected function moveDownload($fileObj, $destinationPath)
      {
          $fs = \wpSPIO()->filesystem();

          $destinationFile = $fs->getFile($destinationPath);
          // If file is non-existing, check directory and write-permissions.
          if (false == $destinationFile->exists())
          {
            $dirObj =  $destinationFile->getFileDir();
            $dirObj->check(true);
          }

          $result = $fileObj->copy($destinationFile);

          if ($result === false)
            return false;

          return $destinationFile;

      }

      private function downloadURLMethod($url, $force = false)
      {
        $executionTime = ini_get('max_execution_time');
        if (! is_numeric($executionTime)) // edge case
        {
           $executionTime = 0;
        }
        $downloadTimeout = max($executionTime - 10, 15);

        $url = $this->setPreferredProtocol(urldecode($url), $force);
        $tempFile = \download_url($url, $downloadTimeout);

        if (is_wp_error($tempFile))
        {
           Log::addError('Failed to Download File from ' . $url , $tempFile);
           Responsecontroller::addData('message', $tempFile->get_error_message());
           return false;
        }

        return $tempFile;
      }

      private function remoteGetMethod($url)
      {
            //get_temp_dir
            $tmpfname = tempnam(get_temp_dir(), 'spiotmp');
            $max_exec = ini_get('max_execution_time'); // Like everything, can't be trusted to be a int.
            $max_exec =  (! is_numeric($max_exec) || $max_exec <= 0) ? 30 : $max_exec;
            $downloadTimeout = max($max_exec - 10, 15);

            $args_for_get = array(
              'stream' => true,
              'filename' => $tmpfname,
              'timeout' => $downloadTimeout,
            );

            $response = wp_remote_get( $url, $args_for_get );

            if (wp_remote_retrieve_response_code($response) == 200 && isset($response['filename']))
            {
                $filepath = $response['filename'];
                return $filepath; // body is the full image is all went well.
            }
            else {
               Log::addError('Wp Remote Get failed', $response);
            }

            return false;
      }

			private function setPreferredProtocol($url, $reset = false) {
		      //switch protocol based on the formerly detected working protocol
		      $settings = \wpSPIO()->settings();

		      if($settings->downloadProto == '' || $reset) {
		          //make a test to see if the http is working
		          $testURL = 'http://' . SHORTPIXEL_API . '/img/connection-test-image.png';
		          $result = download_url($testURL, 10);
		          $settings->downloadProto = is_wp_error( $result ) ? 'https' : 'http';
		      }
		      return $settings->downloadProto == 'http' ?
		              str_replace('https://', 'http://', $url) :
		              str_replace('http://', 'https://', $url);
		  }
}
