<?php
/**
 * Created by PhpStorm.
 * User: Imac
 * Date: 26/09/2018
 * Time: 11:07
 */

namespace Actigraph\ActipageBaseBundle\Services;

use Actigraph\ActipageBaseBundle\Services\IconCaptchaSession;
use GuzzleHttp\Client;
use Psr\Container\ContainerInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;

class CaptchaIconCaptcha
{
    private static $error;
    private static $captcha_id = 0;
    private static $error_messages = array();
    private static $captchaSession;

    private $http,$container,$session, $contentSecurityPolicyNonceService, $captchaService;

    public function __construct(SessionInterface $session,ContentSecurityPolicyNonceService $contentSecurityPolicyNonceService)
    {
        $this->session = $session;
        $this->contentSecurityPolicyNonceService = $contentSecurityPolicyNonceService;
        $this->http = new Client();
    }

    public function getHtmlCaptcha()
    {
        $this->setIconsFolderPath("img/iconCaptcha");
        return '
             <div class="captcha-holder">Icon captcha</div>
                 <script nonce="'.$this->contentSecurityPolicyNonceService->getNonce().'">
                    function isCaptchaFilled(formId){
                        if($(".captcha-holder").hasClass("captcha-success"))
                            return true;
                        else
                            return false;
                    }
            </script>
        ';
    }

    public function isCaptchaValid($postData){
        if(!empty($postData)) {
            // Set the captcha id property
            self::$captcha_id = $postData['captcha-idhf'];

            // If the session is not loaded yet, load it.
            if(!isset(self::$session)) {
                self::$captchaSession = new IconCaptchaSession(self::$captcha_id, 'light', $this->session);
            }

            // Check if the captcha ID is set.
            if(!isset($postData['captcha-idhf']) || !is_numeric($postData['captcha-idhf'])
                || !self::$captchaSession->exists($postData['captcha-idhf'])) {
                self::$error = json_encode(array('id' => 4, 'error' => ((!empty(self::$error_messages[3]))
                    ? self::$error_messages[3] : 'The captcha ID was invalid.')));
                return false;
            }

            // Check if the hidden captcha field is set.
            if(!empty($postData['captcha-hf'])) {

                // If the hashes match, the form can be submitted. Return true.
                if(self::$captchaSession->completed === true && self::getCorrectIconHash() === $postData['captcha-hf']) {
                    return true;
                } else {
                    self::$error = json_encode(array('id' => 1, 'error' => ((!empty(self::$error_messages[0]))
                        ? self::$error_messages[0] : 'Vous avez séléctionné la mauvaise image')));
                }
            } else {
                self::$error = json_encode(array('id' => 2, 'error' => ((!empty(self::$error_messages[1]))
                    ? self::$error_messages[1] : 'Aucune image n\'a été séléctionnée')));
            }
        } else {
            self::$error = json_encode(array('id' => 3, 'error' => ((!empty(self::$error_messages[0]))
                ? self::$error_messages[0] : 'Vous n\'avez pas soumis le formulaire')));
        }

        return false;
    }

    public function removeCaptchaParamFromPostData($data){
        if(isset($data["captcha-idhf"]))
            unset($data["captcha-idhf"]);
        if(isset($data["captcha-hf"]))
            unset($data["captcha-hf"]);
        return $data;
    }

    public function setIconsFolderPath($file_path) {
        $capthcaSession = $this->session->get("icon_captcha", array());
        $capthcaSession["icon_path"] = (is_string($file_path)) ? $file_path : '';
        $this->session->set("icon_captcha", $capthcaSession);
    }

    public function setIconNoiseEnabled($noise) {
        $capthcaSession = $this->session->get("icon_captcha", array());
        $capthcaSession["icon_noise"] = (is_bool($noise)) ? $noise : false;
        $this->session->set("icon_captcha", $capthcaSession);
    }

    public function getCaptchaData($theme, $captcha_id){
        $a = mt_rand(1, 91); // Get a random number (correct image)
        $b = 0; // Get another random number (incorrect image)

        // Set the captcha id property
        self::$captcha_id = $captcha_id;

        // Load the session data, if there is any present.
        // Default data will be used in case no data exists.
        self::$captchaSession = new IconCaptchaSession($captcha_id, $theme, $this->session);

        // Pick a random number for the incorrect icon.
        // Loop until a number is found which doesn't match the correct icon ID.
        while($b === 0) {
            $c = mt_rand(1, 91);
            if($c !== $a) $b = $c;
        }

        $d = -1; // At which position the correct hash will be stored in the array.
        $e = array(); // Array containing the hashes

        // Pick a random number for the correct icon.
        // Loop until a number is found which doesn't match the previously clicked icon ID.
        while($d === -1) {
            $f = mt_rand(1, 5);
            $g = (self::$captchaSession->last_clicked > -1) ? self::$captchaSession->last_clicked : 0;

            if($f !== $g) $d = $f;
        }

        for($i = 1; $i < 6; $i++) {
            if($i === $d) {
                array_push($e, self::getImageHash('icon-' . $a . '-' . $i));
            } else {
                array_push($e, self::getImageHash('icon-' . $b . '-' . $i));
            }
        }

        // Unset the previous session data
        self::$captchaSession->clear();

        // Set (or override) the hashes and reset the icon request count.
        self::$captchaSession->hashes = array($a, $b, $e); // correct id, incorrect id, hashes
        self::$captchaSession->correct_hash = $e[$d - 1];
        self::$captchaSession->icon_requests = 0;
        self::$captchaSession->save();

        // Return the JSON encoded array
        return json_encode($e);

    }

    public function setSelectedAnswer($post){
        if(!empty($post)) {

            // Check if the captcha ID is set.
            if(!isset($_POST['cID']) || !is_numeric($_POST['cID'])) {
                return false;
            }

            // Set the captcha id property
            self::$captcha_id = $_POST['cID'];

            // If the session is not loaded yet, load it.
            if(!isset(self::$captchaSession)) {
                self::$captchaSession = new IconCaptchaSession(self::$captcha_id, 'light', $this->session);
            }

            // Check if the hash is set and matches the correct hash.
            if(isset($post['pC']) && ($this->getCorrectIconHash() === $post['pC'])) {
                self::$captchaSession->completed = true;

                // Unset the data to at least save some space in the session.
                self::$captchaSession->clear();
                self::$captchaSession->save();

                return true;
            } else {
                self::$captchaSession->completed = false;
                self::$captchaSession->save();

                // Set the clicked icon ID
                if(in_array($_POST['pC'], self::$captchaSession->hashes[2])) {
                    $i = array_search($_POST['pC'], self::$captchaSession->hashes[2]);
                    self::$captchaSession->last_clicked = $i + 1;
                }
            }
        }

        return false;
    }

    public function getIconFromHash($hash = null, $captcha_id = null){
        // Check if the hash and captcha id are set
        if(!empty($hash) && (isset($captcha_id) && $captcha_id > -1)) {

            // Set the captcha id property
            self::$captcha_id = $captcha_id;

            // If the session is not loaded yet, load it.
            if(!isset(self::$captchaSession)) {
                self::$captchaSession = new IconCaptchaSession(self::$captcha_id, 'light', $this->session);
            }

            // Check the amount of times an icon has been requested
            if(self::$captchaSession->icon_requests >= 5) {
                header('HTTP/1.1 403 Forbidden');
                exit;
            }

            // Update the request counter
            self::$captchaSession->icon_requests += 1;
            self::$captchaSession->save();
            // Check if the hash is present in the session data
            if(in_array($hash, self::$captchaSession->hashes[2])) {
                $icons_path = $this->session->get("icon_captcha")['icon_path']; // Icons folder path

                $icon_file = $icons_path . ((substr($icons_path, -1) === '/') ? '' : '/') . self::$captchaSession->theme . '/icon-' .
                    (($this->getCorrectIconHash() === $hash) ? self::$captchaSession->hashes[0] : self::$captchaSession->hashes[1]) . '.png';

                // Check if the icon exists
                if (is_file($icon_file)) {

                    // Check if noise is enabled or not.
                    $add_noise = (isset($this->session->get("icon_captcha")['icon_noise'])
                        && $this->session->get("icon_captcha")['icon_noise']);

                    // If noise is enabled, add the random pixel noise.
                    if($add_noise) {
                        $icon = imagecreatefrompng($icon_file);
                        $noise_color = imagecolorallocatealpha($icon, 0, 0, 0, 126);

                        // Add some random pixels to the icon
                        for ($i = 0; $i < 5; $i++) {
                            $randX = ($i < 3) ? mt_rand(0, 2) : mt_rand(28, 30);
                            $randY = ($i < 3) ? mt_rand(0, 15) : mt_rand(16, 30);

                            imagesetpixel($icon, $randX, $randY, $noise_color);
                        }
                    }

                    // Set the content type header to the PNG MIME-type.
                    header('Content-type: image/png');

                    // Disable caching of the icon, even though the images might
                    // be 'random' due to the added pixels.
                    header('Expires: 0');
                    header('Cache-Control: no-cache, no-store, must-revalidate');
                    header('Cache-Control: post-check=0, pre-check=0', false);
                    header('Pragma: no-cache');

                    // Show the image and exit the code
                    if($add_noise && isset($icon)) {
                        imagepng($icon);
                        imagedestroy($icon);
                    } else {
                        readfile($icon_file);
                    }

                    exit;
                }
            }
        }
    }

    public function getImageHash($image = null) {
        if(!isset(self::$captchaSession)) {
            self::$captchaSession = new IconCaptchaSession(self::$captcha_id, 'light', $this->session);
        }

        return (!empty($image) && (isset(self::$captcha_id) && is_numeric(self::$captcha_id)))
            ? hash('tiger192,3', $image . hash('crc32b', uniqid())) : '';
    }

    public function getCorrectIconHash() {
        if(!isset(self::$captchaSession)) {
            self::$captchaSession = new IconCaptchaSession(self::$captcha_id, self::$captcha_id, 'light', $this->session);
        }

        return (isset(self::$captcha_id) && is_numeric(self::$captcha_id))
            ? self::$captchaSession->correct_hash : '';
    }

    public function setErrorMessages($messages = array()) {
        if(!empty($messages)) self::$error_messages = $messages;
    }

    public function getErrorMessage() {
        return self::$error;
    }

    public static function validateSubmission($post) {

    }

}