<?php
/**
* @package   BaForms
* @author    Balbooa http://www.balbooa.com/
* @copyright Copyright @ Balbooa
* @license   http://www.gnu.org/licenses/gpl.html GNU/GPL
*/

namespace Balbooa\Component\Forms\Site\Helper;

defined('_JEXEC') or die;

use Balbooa\Component\Forms\Administrator\Helper\ExtensionInfo;
use Balbooa\Component\Forms\Administrator\Helper\Filesystem\File;
use Balbooa\Component\Forms\Administrator\Helper\Filesystem\Folder;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Uri\Uri;

abstract class BaformsHelper 
{
    public static $state;
    public static $about;
    public static $shortCodes;
    public static $design;
    public static $fonts = [];
    public static $fontawesome;
    public static $material;
    public static $conditionLogic;
    public static $countries;
    public static $image_path;
    public static bool $isClosed = false;
    public static string $closedFormMessage = '';
    
    public static function checkUserPoll($field)
    {
        $ip = $_SERVER['REMOTE_ADDR'];
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('COUNT(id)')
            ->from('#__baforms_poll_results')
            ->where('form_id = '.$field->form_id)
            ->where('field_id = '.$field->id)
            ->where('ip = '.$db->quote($ip));
        $db->setQuery($query);
        $count = $db->loadResult();
        $allow = $count == 0;

        return $allow;
    }

    public static function getPollResults($id, $items)
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('*')
            ->from('#__baforms_poll_results')
            ->where('field_id = '.$id);
        $db->setQuery($query);
        $array = $db->loadObjectList();
        $count = count($array);
        $results = new \stdClass();
        $order = [];
        foreach ($array as $value) {
            if (!isset($results->{$value->value})) {
                $results->{$value->value} = new \stdClass();
                $results->{$value->value}->votes = 0;
            }
            $results->{$value->value}->votes++;
        }
        $percent = 0;
        foreach ($results as $key => $value) {
            $value->percent = round($value->votes * 100 / $count, 1);
            $percent += $value->percent;
            $order[(string)$key] = $value->percent;
        }
        arsort($order);
        $i = 0;
        foreach ($order as $key => $value) {
            $results->{$key}->order = $i;
            $i++;
        }
        foreach ($items as $key => $item) {
            if (!isset($results->{$item->key})) {
                $obj = new \stdClass();
                $obj->votes = $obj->percent = 0;
                $obj->order = $i;
                $results->{$item->key} = $obj;
            }
            $results->{$item->key}->title = $item->title;
        }

        return $results;
    }

    public static function getFormShortCodes($id)
    {
        $user = Factory::getUser();
        $doc = Factory::getDocument();
        $input = Factory::getApplication()->input;
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('title')
            ->from('#__baforms_forms')
            ->where('id = '.$id);
        $db->setQuery($query);
        $formTitle = $db->loadResult();
        $task = $input->get('task', '', 'string');
        $page_id = $input->get('id', 0, 'int');
        if (is_array($page_id) || $task == 'loadAjaxForm') {
            $page_id = 0;
        }
        $time = time();
        self::$shortCodes = new \stdClass();
        self::$shortCodes->{'[Username]'} = $user->id != 0 ? $user->username : '';
        self::$shortCodes->{'[User Name]'} = $user->id != 0 ? $user->name : '';
        self::$shortCodes->{'[User Email]'} = $user->id != 0 ? $user->email : '';
        self::$shortCodes->{'[User ID]'} = strval($user->id);
        self::$shortCodes->{'[User IP Address]'} = $_SERVER['REMOTE_ADDR'];
        self::$shortCodes->{'[Date]'} = HTMLHelper::date($time, 'j F Y');
        self::$shortCodes->{'[Time]'} = HTMLHelper::date($time, 'H:i:s');
        self::$shortCodes->{'[Time AM / PM]'} = HTMLHelper::date($time, 'h:i:s A');
        self::$shortCodes->{'[Page Title]'} = $task == 'loadAjaxForm' ? '[Page Title]' : $doc->title;
        self::$shortCodes->{'[Page URL]'} = $task == 'loadAjaxForm' ? '[Page URL]' : $_SERVER['REQUEST_URI'];
        self::$shortCodes->{'[Page ID]'} = strval($page_id);
        self::$shortCodes->{'[Form Title]'} = $formTitle;
        self::$shortCodes->{'[Form ID]'} = strval($id);
        self::$shortCodes->{'[Submission ID]'} = '';
    }

    public static function renderDefaultValue($value, $slash = false)
    {
        foreach (self::$shortCodes as $ind => $shortCode) {
            if ($slash) {
                $shortCode = addcslashes($shortCode, '\'');
            }
            $value = str_replace($ind, $shortCode, $value);
        }
        $value = preg_replace('/\[Field ID=\d+]/', '', $value);
        preg_match_all('/\[URL parameter = (.*?)]/', $value, $matches, PREG_SET_ORDER);
        if (!empty($matches)) {
            $input = Factory::getApplication()->input;
            foreach ($matches as $match) {
                $result = $input->get->get($match[1], '', 'string');
                $value = str_replace($match[0], $result, $value);
            }
        }
        preg_match_all('/\[SQL query = (.*?)]/', $value, $matches, PREG_SET_ORDER);
        if (!empty($matches)) {
            $db = Factory::getDbo();
            foreach ($matches as $match) {
                try {
                    $query = $match[1];
                    $db->setQuery($query);
                    $result = $db->loadResult();
                    $value = str_replace($match[0], $result, $value);
                } catch (\Exception $e) {
                    $value = str_replace($match[0], '', $value);
                }
            }
        }

        return $value;
    }

    public static function getMapsKey()
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true);
        $query->select('`key`')
            ->from('`#__baforms_api`')
            ->where('`service` = '.$db->quote('google_maps'));
        $db->setQuery($query);
        $key = $db->loadResult();
        return $key;
    }

    public static function loadJQuery($id)
    {
        $params = ComponentHelper::getParams('com_baforms');
        $jquery = $params->get('load_jquery', 1);
        
        return $jquery;
    }

    public static function getFormOptions()
    {
        $obj = new \stdClass();
        $dir = JPATH_ROOT.'/administrator/components/com_baforms/assets/json/';
        $files = Folder::files($dir);
        foreach ($files as $value) {
            $str = File::read($dir.$value);
            $key = str_replace('.json', '', $value);
            $obj->{$key} = json_decode($str);
        }

        return $obj;
    }

    public static function renderFormHTML($body)
    {
        $app = Factory::getApplication();
        $input = $app->input;
        $option = $input->get('option', '', 'string');
        $view = $input->get('view', '', 'string');
        if ($option == 'com_sppagebuilder' && $view == 'form') {
            return $body;
        }
        $regex = '/\[forms ID=+(.*?)\]/i';
        $array = [];
        preg_match_all($regex, $body, $matches, PREG_SET_ORDER);
        $formOptions = null;
        foreach ($matches as $index => $match) {
            $id = $match[1] * 1;
            if (!empty($id) && is_numeric($id) && self::checkForm($id)) {
                if (!isset($array[$id])) {
                    if (empty($formOptions)) {
                        $formOptions = self::getFormOptions();
                        $str = File::read(JPATH_ROOT.'/components/com_baforms/libraries/countries/countries.json');
                        self::$countries = json_decode($str);
                    }
                    CompatibleCheck::checkForm($id, $formOptions);
                    $array[$id] = (object) [
                        'html' => self::drawHTMLPage($id),
                        'design' => self::$design,
                        'conditionLogic' => self::$conditionLogic,
                    ];
                }
                $html = $array[$id]->html;
                $body = @preg_replace("|\[forms ID=".$id."\]|", addcslashes($html, '\\$'), $body, 1);
            }
        }
        if (!empty($array)) {
            $body = self::drawScripts($array) . $body;
        }

        return $body;
    }
    
    public static function drawScripts($cid): string
    {
        $doc = Factory::getDocument();
        $scripts = $doc->_scripts;
        $array = [];
        $loadFormsMap = new \stdClass();
        $loadFormsMap->load = false;
        foreach ($scripts as $key => $script) {
            if (strpos($key, 'maps.googleapis.com/maps/api/js?libraries=places')) {
                $loadFormsMap->load = false;
            }
            $key = explode('/', $key);
            $array[] = end($key);
        }
        foreach ($cid as $id => $value) {
            $signatures = self::getScriptItemsCount($id, 'signature');
            if (!$loadFormsMap->load && (self::getScriptItemsCount($id, 'map') || self::getScriptItemsCount($id, 'address'))) {
                $loadFormsMap->load = true;
                $loadFormsMap->api_key = self::getMapsKey();
            }
        }
        $loadMapJSON = json_encode($loadFormsMap);
        $html = '';
        include JPATH_ROOT.'/components/com_baforms/tmpl/form/style.php';
        $html .= $out;
        $src = Uri::root().'components/com_baforms/assets/css/ba-style.css?'.self::$about->version;
        $link = "\n\t<link href=\"%s\" rel=\"stylesheet\" type=\"text/css\">";
        $html .= sprintf($link, $src);
        if (self::$fontawesome) {
            $src = Uri::root() . 'media/templates/administrator/atum/css/vendor/fontawesome-free/fontawesome.css';
            $html .= sprintf($link, $src);
        }
        if (self::$material) {
            $src = Uri::root().'components/com_baforms/assets/icons/material/material.css';
            $html .= sprintf($link, $src);
        }
        if (!empty(self::$fonts)) {
            $fontsStr = '';
            foreach (self::$fonts as $font) {
                if (!empty($fontsStr)) {
                    $fontsStr .= '%7C';
                }
                $fontsStr .= $font;
            }
            $src = '//fonts.googleapis.com/css?family='.$fontsStr;
            $html .= sprintf($link, $src);
        }

        if (self::loadJQuery($id) == 0) {
            
        } else if (!in_array('jquery.min.js', $array) && !in_array('jquery.js', $array)) {
            if (JVERSION >= '4.0.0') {
                $src = Uri::root(true).'/media/vendor/jquery/js/jquery.min.js';
            } else {
                $src = Uri::root(true).'/media/jui/js/jquery.min.js';
            }
            $html .= self::buildScript($src);
        }
        $src = Uri::root().'components/com_baforms/assets/js/ba-form.js?'.self::$about->version;
        $html .= self::buildScript($src);
        
        return $html;
    }

    protected static function buildScript(string $src): string
    {
        $nonce = Factory::getApplication()->get('csp_nonce');
        $nonceAttr = $nonce ? ' nonce="' . $nonce . '"' : '';

        return <<<HTML
            <script $nonceAttr src="$src"></script>
        HTML;
    }

    public static function getScriptItemsCount($id, $type)
    {
    	$db = Factory::getDbo();
    	$query = $db->getQuery(true)
    		->select('COUNT(id)')
    		->from('#__baforms_items')
            ->where('form_id = '.$id)
    		->where('type = '.$db->quote($type));
		$db->setQuery($query);
		$count = $db->loadResult();

		return $count > 0;
    }

    public static function setAppLicense()
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('*')
            ->from('#__baforms_api')
            ->where('service = '.$db->quote('balbooa'));
        $db->setQuery($query);
        $balbooa = $db->loadObject();
        $balbooa->key = '{}';
        $db->updateObject('#__baforms_api', $balbooa, 'id');
    }

    public static function setAppLicenseActivation()
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('*')
            ->from('#__baforms_api')
            ->where('service = '.$db->quote('balbooa_activation'));
        $db->setQuery($query);
        $balbooa = $db->loadObject();
        $balbooa->key = '{}';
        $db->updateObject('#__baforms_api', $balbooa, 'id');
    }

    public static function renderPrice($value, $thousand, $separator, $decimals)
    {
        $delta = $value < 0 ? '-' : '';
        $value = str_replace('-', '', $value);
        $priceArray = explode('.', $value);
        $priceThousand = $priceArray[0];
        $priceDecimal = isset($priceArray[1]) ? $priceArray[1] : '';
        $value = '';
        if (($pricestrlen = strlen($priceThousand)) > 3 && $thousand != '') {
            for ($i = 0; $i < $pricestrlen; $i++) {
                if ($i % 3 == 0 && $i != 0) {
                    $value .= $thousand;
                }
                $value .= $priceThousand[$pricestrlen - 1 - $i];
            }
            $value = strrev($value);
        } else {
            $value .= $priceThousand;
        }
        if ($decimals != 0) {
            $value .= $separator;
            for ($i = 0; $i < $decimals; $i++) {
                $value .= isset($priceDecimal[$i]) ? $priceDecimal[$i] : '0';
            }
        }

        return $delta.$value;
    }

    public static function renderPollResults($field)
    {
        self::prepareCondition('[]', 0);
        Factory::getLanguage()->load('com_baforms', JPATH_ADMINISTRATOR);
        $renderResults = true;
        include JPATH_ROOT.'/components/com_baforms/tmpl/form/poll.php';

        return $out;
    }

    public static function isClosedForm(object $options, $form_id):bool
    {
        $flag = false;
        $db = Factory::getDbo();
        if (!empty($options->limit->count)) {
            $query = $db->getQuery(true)
                ->select('COUNT(id)')
                ->from('#__baforms_submissions')
                ->where('form_id = ' . $form_id);
            $db->setQuery($query);
            $count = $db->loadResult();
            $flag = (int)$options->limit->count <= (int)$count;
        }
        if (!$flag && !empty($user_id = Factory::getUser()->id) && !empty($options->limit->user_id)) {
            $query = $db->getQuery(true)
                ->select('COUNT(id)')
                ->from('#__baforms_submissions')
                ->where('form_id = ' . $form_id)
                ->where('user_id = ' . $user_id);
            $db->setQuery($query);
            $count = $db->loadResult();
            $flag = (int)$options->limit->user_id <= (int)$count;
        }
        if (!$flag && !empty($options->limit->user_ip)) {
            $user_ip = $_SERVER['REMOTE_ADDR'];
            $query = $db->getQuery(true)
                ->select('COUNT(id)')
                ->from('#__baforms_submissions')
                ->where('form_id = ' . $form_id)
                ->where('user_ip = ' . $db->quote($user_ip));
            $db->setQuery($query);
            $count = $db->loadResult();
            $flag = (int)$options->limit->user_ip <= (int)$count;
        }
        if (!$flag && !empty($options->limit->end_date)) {
            $config = Factory::getApplication()->getConfig();
            $timezone = $config->get('offset', 'UTC');
            $now = new \DateTime('now', new \DateTimeZone($timezone));
            $flag = $now->format('Y-m-d H:i:s') > $options->limit->end_date;
        }
        self::$closedFormMessage = $options->limit->message ?? '';

        return $flag;
    }
    
    public static function drawHTMLPage($id)
    {
        self::getFormShortCodes($id);
        $pages = self::getPages($id);
        $pageCount = count($pages);
        $settings = self::getFormSettings($id);
        $navigation = json_decode($settings->navigation);
        $closedPoll = false;
        self::prepareCondition($settings->condition_logic, $id);
        self::$isClosed = false;
        self::$design = json_decode($settings->design);
        self::$design->css = $settings->css;
        self::$design->js = $settings->js;
        if (self::$design->field->typography->{'font-family'} !='inherit'
            && !in_array(self::$design->field->typography->{'font-family'}, self::$fonts)) {
            self::$fonts[] = self::$design->field->typography->{'font-family'};
        }
        if (self::$design->label->typography->{'font-family'} !='inherit'
            && !in_array(self::$design->label->typography->{'font-family'}, self::$fonts)) {
            self::$fonts[] = self::$design->label->typography->{'font-family'};
        }
        $path = JPATH_ROOT.'/components/com_baforms/tmpl/form/';
        Factory::getLanguage()->load('com_baforms', JPATH_ADMINISTRATOR);
        $url = Uri::root().'index.php?option=com_baforms';
        /*$url = Route::_('index.php?option=com_baforms');
        if (substr($url, -1) === '/') {
            $url = substr($url, 0, -1);
        }*/
        DesignHelper::getInstance()->setAccessibility(self::$design->theme->accessibility ?? false);
        include $path.'form.php';
        $input = Factory::getApplication()->input;
        $option = $input->get('option', '', 'string');
        if (self::$fontawesome !== true/* && $option != 'com_gridbox'*/) {
            $array = [
                'fa fa-',
                'fab fa-',
                'fal fa-',
                'far fa-',
                'fas fa-',
                'fa-fw',
                'fa-solid',
                'fa-regular',
                'fa-brands',
                'fa-classic'
            ];
            foreach ($array as $value) {
                if (str_contains($out, $value)) {
                    self::$fontawesome = true;
                    break;
                }
            }
        }
        if (self::$material !== true && $option != 'com_gridbox') {
            self::$material = strpos($out, 'zmdi zmdi-') !== false;
        }
        
        return $out;
    }

    public static function prepareCondition($condition_logic, $id)
    {
        self::$conditionLogic = new \stdClass();
        self::$conditionLogic->hidden = [];
        self::$conditionLogic->conditions = [];
        $conditions = json_decode($condition_logic);
        $types = ['radio', 'select', 'checkbox', 'selectMultiple'];
        foreach ($conditions as $condition) {
            if (!$condition->publish) {
                continue;
            }
            $flags = [];
            foreach ($condition->when as $when) {
                $field = self::getFormItem($id, $when->field);
                if (empty($field)) {
                    continue;
                }
                $options = json_decode($field->options);
                $value = '';
                if (in_array($field->type, $types)) {
                    $replaced = false;
                    foreach ($options->items as $item) {
                        if (!$replaced && $when->value == $item->key) {
                            $replaced = true;
                            $when->value = strip_tags($item->title);
                        }
                        if ($item->default) {
                            $value .= strip_tags($item->title);
                        }
                    }
                } else if ($field->type == 'input') {
                    $value = self::renderDefaultValue($options->default);
                    $value = preg_replace('/\[Field ID=+(.*?)\]/i', '', $value);
                } else if ($field->type == 'calendar') {
                    $value = $options->default == 'today' ? HTMLHelper::date(time(), 'j F Y') : '';
                }
                switch ($when->state) {
                    case 'equal':
                        $flags[] = $value == $when->value;
                        break;
                    case 'not-equal':
                        $flags[] = $value != $when->value;
                        break;
                    case 'not-empty':
                        $flags[] = $value != '';
                        break;
                    case 'empty':
                        $flags[] = $value == '';
                        break;
                    case 'greater':
                        $flags[] = (is_numeric($value) ? $value * 1 : $value) > (is_numeric($when->value) ? $when->value * 1 : $when->value);
                        break;
                    case 'less':
                        $flags[] = (is_numeric($value) ? $value * 1 : $value) < (is_numeric($when->value) ? $when->value * 1 : $when->value);
                        break;
                    case 'contain':
                        $flags[] = (strpos($value, $when->value) !== false);
                        break;
                    case 'not-contain':
                        $flags[] = (strpos($value, $when->value) === false);
                        break;
                }
            }
            if (empty($flags)) {
                continue;
            }
            $flag = ($condition->operation == 'AND' && !in_array(false, $flags))
                || ($condition->operation == 'OR' && in_array(true, $flags));
            foreach ($condition->do as $do) {
                if (($do->action == 'show' && !$flag) || ($do->action == 'hide' && $flag)) {
                    self::$conditionLogic->hidden[] = 'baform-'.$do->field;
                }
            }
            self::$conditionLogic->conditions[] = $condition;
        }
    }

    public static function prepareHelper(): void
    {
        self::$about = ExtensionInfo::get();
        self::$state = self::checkFormsActivation();
        $params = ComponentHelper::getParams('com_media');
        self::$image_path = $params->get('file_path', 'images');
    }

    public static function getFormItem($id, $key)
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('*')
            ->from('#__baforms_items')
            ->where('form_id = '.$id)
            ->where('`key` = '.$db->quote('baform-'.$key))
            ->order('`column_id` ASC');
        $db->setQuery($query);
        $items = $db->loadObject();
        
        return $items;
    }

    public static function getFormColumns($key, $id)
    {
    	$db = Factory::getDbo();
    	$query = $db->getQuery(true)
    		->select('*')
    		->from('#__baforms_columns')
    		->where('form_id = '.$id)
    		->where('`key` = '.$db->quote($key));
		$db->setQuery($query);
		$obj = $db->loadObject();

		return $obj;
    }

    public static function getFormItems($id, $key)
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('*')
            ->from('#__baforms_items')
            ->where('form_id = '.$id)
            ->where('`parent` = '.$db->quote($key))
            ->order('`column_id` ASC');
        $array = [$db->quote('input'), $db->quote('submit'), $db->quote('text'), $db->quote('image'), $db->quote('html')];
        if (self::$about->tag != 'pro' || !isset(self::$state->data)) {
            $query->where('type in ('.implode(',', $array).')');
        }
        $db->setQuery($query);
        $items = $db->loadObjectList();
        
        return $items;
    }

    public static function getFormSettings($id)
    {
    	$db = Factory::getDbo();
    	$query = $db->getQuery(true)
    		->select('*')
    		->from('#__baforms_forms_settings')
    		->where('form_id = '.$id);
		$db->setQuery($query);
		$obj = $db->loadObject();

		return $obj;
    }

    public static function getPages($id)
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('*')
            ->from('#__baforms_pages')
            ->where('form_id = '.$id)
            ->order('`order_index` ASC');
        $db->setQuery($query);
        $item = $db->loadObjectList();
        
        return $item;
    }

    public static function checkFormsActivation(string $service = 'balbooa_activation')
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('`key`')
            ->from('#__baforms_api')
            ->where('service = ' . $db->quote($service));
        $db->setQuery($query);
        $balbooa = $db->loadResult();
        $state = json_decode($balbooa);

        return $state;
    }
    
    public static function getFormsFooter($id)
    {
        $copyright = self::$about->tag != 'pro';
        include JPATH_ROOT.'/components/com_baforms/tmpl/form/footer.php';

        return $out;
    }
    
    public static function checkForm($id)
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('COUNT(id)')
            ->from('#__baforms_forms')
            ->where('id='.$id)
            ->where('published = 1');
        $db->setQuery($query);
        $count = $db->loadResult();

        return $count > 0;
    }
}

BaformsHelper::prepareHelper();