<?php
    /**
     * @package     Formea.Plugin
     * @subpackage  element
     *
     * @copyright   Copyright (C) 2010-2023 Feseur Sdn Bhd. All rights reserved.
     * @license     GNU General Public License version 2 or later; see LICENSE.txt
     * @version     1.0.2
     */
// no direct access
    defined('_JEXEC') or die();

    use Feseur\Library\FsrResponse;
    use Joomla\CMS\Component\ComponentHelper;
    use Joomla\Filesystem\File;
    use Joomla\Filesystem\Folder;
    use Joomla\CMS\Language\Text;
    use Joomla\CMS\Uri\Uri;
    use Joomla\Component\Formea\Site\Libraries\FormeaEltype;
    use Joomla\CMS\Factory;
    use Joomla\Component\Formea\Site\Libraries\FormeaSubmissionElement;
    use Joomla\Component\Formea\Site\Libraries\FormeaValidation;
    use Joomla\Database\DatabaseDriver;
    use Joomla\Filesystem\Path;

    class FormeaFileInput extends FormeaEltype
    {
        public function __construct($config = [])
        {
            parent::__construct($config);
        }

        public function getInput($class = [], $inputAttributes = [], $langTagUnderscore = '', $preview = false, $labelSetting = null)
        {
            $themeClass = $this->getThemeClass();
            if (empty($langTagUnderscore))
            {
                $langTagUnderscore = $this->langTagUnderscore;
            }

            // $submittedData = $this->getSubmittedElementData();

            $default_value = '';
            if (isset($inputAttributes['value']))
            {
                unset($inputAttributes['value']);
            }


            $classAttr = [];

            $classAttr[] = $themeClass->getInputClass();
            if (!empty($class))
            {
                $classAttr = array_merge($classAttr, $class);
            }

            $input     = '<input class="' . implode(' ', $classAttr) . '" ';
            $inputType = 'file';

            $input .= 'type="' . $inputType . '"';
            if (!$preview)
            {
                $input .= 'name="' . $this->formatElementName() . '[]"';
                if ((int) $this->params->get('is_multiple', 0) > 0)
                {
                    $inputAttributes['multiple'] = 'true';
                }
                else
                {
                    if (isset($inputAttributes['multiple']))
                    {
                        unset($inputAttributes['multiple']);
                    }
                }

                $allowed_extension = '';
                $mimeTypes         = '';
                if ((int) $this->params->get('use_joomla_setting', 0) > 0)
                {
                    $mediaConfig       = ComponentHelper::getParams('com_media');
                    $allowed_extension = $mediaConfig->get('restrict_uploads_extensions', 'jpg,jpeg,png');
                    $mimeTypes         = $mediaConfig->get('upload_mime');
                }
                else
                {
                    $allowed_extension = $this->params->get('custom_allowed_extension', 'jpg,jpeg,png');
                    $mimeTypes         = $this->params->get('custom_allowed_mimetype');
                }
                $acceptAttributes = [];
                if (!empty($allowed_extension))
                {
                    $allowed_extension_array = explode(',', $allowed_extension);
                    $totalAllowed            = count($allowed_extension_array);
                    for ($i = 0; $i < $totalAllowed; $i++)
                    {
                        $acceptAttributes[] = '.' . trim($allowed_extension_array[$i]);
                    }
                }
                if (!empty($mimeTypes))
                {
                    $mimeTypes_array = explode(',', $mimeTypes);
                    $totalMimes      = count($mimeTypes_array);
                    for ($j = 0; $j < $totalMimes; $j++)
                    {
                        $acceptAttributes[] = trim($mimeTypes_array[$j]);
                    }
                }
                if (!empty($acceptAttributes))
                {
                    $inputAttributes['accept'] = implode(',', $acceptAttributes);
                }
            }

            foreach ($inputAttributes as $key => $value)
            {
                $input .= ' ' . $key . '="' . $value . '" ';
            }

            $input .= 'id="' . $this->formatElementId() . '" />';

            return $input;
        }

        protected function _validateInput($element)
        {
            $retObject = new FsrResponse(true);
            $result    = (object) [
                'hasError' => false,
                'msg'      => ''
            ];
            $filenames = [];

            if (empty($element->submitted_value))
            {
                $retObject->setResult($result);

                return [
                    'filenames' => $filenames,
                    'validate'  => $retObject
                ];
            }

            $phpErrors         = $this->errorMsgs();
            $params            = $this->params;
            $maxFileSizeMB     = (int) $params->get('custom_max_size', 2);
            $allowedExtensions = $params->get('custom_allowed_extension');
            $allowedMimetypes  = $params->get('custom_allowed_mimetype');

            if ((int) $params->get('use_joomla_setting', 0) > 1)
            {
                $mediaConfig       = ComponentHelper::getParams('com_media');
                $maxFileSizeMB     = (int) $mediaConfig->get('upload_maxsize', 2);
                $allowedExtensions = $mediaConfig->get('restrict_uploads_extensions');
                $allowedMimetypes  = $mediaConfig->get('upload_mime');
            }

            $allowedExtensionsArray = explode(',', $allowedExtensions);
            $allowedMimetypesArray  = explode(',', $allowedMimetypes);

            foreach ($element->submitted_value as $file)
            {
                $filename  = $file['name'];
                $fileError = (int) $file['error'];

                if ($fileError > 0 && $fileError != 4)
                {
                    $result->hasError = true;
                    $result->msg      = $phpErrors[$fileError];
                    break;
                }

                if ($fileError == 4)
                {
                    continue;
                }

                $filenames[] = $filename;

                $uploadedExtension = pathinfo($filename, PATHINFO_EXTENSION);
                if (!$this->isValidExtension($uploadedExtension, $allowedExtensionsArray))
                {
                    $result->hasError = true;
                    $result->msg      = Text::_('FIE_FORMEA_INVALID_FILE_TYPE') . ' ' . $uploadedExtension;
                    break;
                }

                if (!$this->isValidMimeType($file['type'], $allowedMimetypesArray))
                {
                    $result->hasError = true;
                    $result->msg      = Text::_('FIE_FORMEA_INVALID_FILE_TYPE') . ' ' . $file['type'];
                    break;
                }

                if ($this->isFileSizeExceeded($file['size'], $maxFileSizeMB))
                {
                    $result->hasError = true;
                    $result->msg      = Text::sprintf('FIE_FORMEA_FILE_S_EXCEED_FILE_SIZE_N', $filename, $maxFileSizeMB);
                    break;
                }
            }

            $retObject->setResult($result);

            return [
                'filenames' => $filenames,
                'validate'  => $retObject
            ];
        }

        private function isValidExtension($extension, $allowedExtensions)
        {
            return in_array($extension, $allowedExtensions);
        }

        private function isValidMimeType($mimeType, $allowedMimetypes)
        {
            foreach ($allowedMimetypes as $allowedMimeType)
            {
                if (fnmatch(trim($allowedMimeType), $mimeType))
                {
                    return true;
                }
            }

            return false;
        }

        private function isFileSizeExceeded($fileSizeBytes, $maxFileSizeMB)
        {
            $fileSizeMB = $fileSizeBytes / (1024 * 1024);

            return $fileSizeMB > $maxFileSizeMB;
        }


        /**
         * @param   mixed                    $submitted_value
         * @param   FormeaSubmissionElement  $element
         * @param   FormeaValidation[]       $validations
         *
         * @return FsrResponse
         *
         * @since 1.0.0
         */
        public function validateInput($submitted_value, $element, $validations = [])
        {

            $retObject        = new FsrResponse();
            $totalValidations = count($validations);
            $result           = [];

            $internalValidation = $this->_validateInput($element);
            $result[]           = (object) ['validation_plugin' => 'Internal File Input Validation', 'result' => $internalValidation['validate']];

            //run the element validations

            $submitted_value = $internalValidation['filenames'];
            if(empty($internalValidation['filenames'])){
                $submitted_value = "";
            }else{
                $submitted_value = implode(',', $internalValidation['filenames']);
            }
            if ($totalValidations > 0)
            {
                for ($i = 0; $i < $totalValidations; $i++)
                {
                    $validatorPath = JPATH_ROOT . '/components/com_formea/plugins/validation/' . $validations[$i]['validation_type'] . '/';
                    $class         = $validations[$i]['validation_type'];
                    if (is_file(Path::clean($validatorPath . $class . '.php')))
                    {
                        require_once $validatorPath . $class . '.php';
                        $config = [
                            'submitted_value' => $submitted_value,
                            'params'          => $validations[$i]['params'],
                            'validation'      => $validations[$i],
                            'value_type'      => 0
                        ];
                        /** @var FormeaValidation $validationClass */
                        $validationClass = new $class($config);
                        // var_dump($validationClass);die;
                        $result[] = (object) ['validation_plugin' => $class, 'result' => $validationClass->validate()];
                    }
                    else
                    {
                        $retObject->setMsg(Text::sprintf('COM_FORMEA_VALIDATION_PLUGIN_S_NOT_FOUND', $validations[$i]['validation_type']));
                    }
                }
            }
            $retObject->setResult($result);
            $retObject->setSuccess(true);

            return $retObject;
        }


        /**
         * @param   FormeaSubmissionElement  $element
         *
         * @return mixed
         *
         * @since 1.0.5
         */
        public function beforeValidatingInput($element)
        {
            $element->is_link = 1;

            return $element;
        }


        /**
         * @param                            $formObject
         * @param                            $submission_id
         * @param   FormeaSubmissionElement  $element
         *
         * @return mixed
         *
         * @since version
         */
        public function afterStoringInDb($formObject, $submission_id, $element)
        {
            $submission_data_id = 0;
            if (!isset($element->element_id) || !isset($element->group_id) || !isset($element->setIndex) || empty($element->submitted_value))
            {
                return $element;
            }

            $container = Factory::getContainer();
            /** @var DatabaseDriver $db */
            $db    = $container->get('DatabaseDriver');
            $query = $db->getQuery(true);
            $query->select('*');
            $query->from($db->quoteName('#__formea_submission_data'));
            $query->where($db->quoteName('field_id') . ' = ' . $db->quote($element->element_id));
            $query->where($db->quoteName('group_id') . ' = ' . $db->quote($element->group_id));
            $query->where($db->quoteName('setIndex') . ' = ' . $db->quote($element->setIndex));
            $query->where($db->quoteName('submission_id') . ' = ' . $db->quote($submission_id));
            $query->where($db->quoteName('form_id') . ' = ' . $db->quote($formObject->id));
            $db->setQuery($query);
            $submission_data = $db->loadObject();
            $query->clear();
            if (empty($submission_data))
            {
                return $element;
            }

            $submission_data_id = $submission_data->id;

            if (!empty($element->submitted_value))
            {
                $uploadDirectory = $this->params->get('upload_path', 'media/com_formea/uploads');
                $uploadDirectory = rtrim($uploadDirectory, '/');
                $uploadDirectory = $uploadDirectory . '/' . $formObject->alias . '/' . $submission_data_id;
                if (!is_dir(Path::clean($uploadDirectory)))
                {
                    Folder::create($uploadDirectory);
                }
                $uploaded_files     = $element->submitted_value; //an array of files ['name','type','tmp_name','error','size']
                $totalUploadedFiles = count($uploaded_files);
                $dirPath            = [];
                $linkPath           = [];
                $filenames          = [];
                $element->is_link   = 1;
                for ($i = 0; $i < $totalUploadedFiles; $i++)
                {
                    $fileError = (int) $uploaded_files[$i]['error'];
                    if (strlen($uploaded_files[$i]['name']) != 0 && $fileError < 1)
                    {
                        $filename = $uploaded_files[$i]['name'];
                        $prefix   = $this->params->get('filename_prefix');
                        if (!empty($prefix))
                        {
                            $filename = $prefix . $filename;
                        }
                        $uploadingFileName = File::makeSafe($filename);
                        $filenames[]       = $uploadingFileName;
                        $uploadDirectory   .= '/';
                        File::upload($uploaded_files[$i]['tmp_name'], $uploadDirectory . $uploadingFileName, false, true);
                        $dirPath[]  = $uploadDirectory . $uploadingFileName;
                        $linkPath[] = Uri::root() . trim($uploadDirectory, '/') . '/' . $uploadingFileName;
                    }
                }
                $element->submitted_value = implode(', ', $filenames);
                $element->dir_path        = $dirPath;
                $element->link_path       = $linkPath;

                $upd = (object) [
                    'id'          => $submission_data_id,
                    'is_link'     => 1,
                    'field_value' => implode(',', $filenames),
                    'link_path'   => json_encode($element->link_path),
                    'dir_path'    => json_encode($element->dir_path),
                ];
                $db->updateObject('#__formea_submission_data', $upd, 'id');
            }

            return $element;
        }

        protected function errorMsgs()
        {
            $phpFileUploadErrors = array(
                0 => Text::_('FIE_FORMEA_UPLOAD_ERROR_0'),
                1 => Text::_('FIE_FORMEA_UPLOAD_ERROR_1'),
                2 => Text::_('FIE_FORMEA_UPLOAD_ERROR_2'),
                3 => Text::_('FIE_FORMEA_UPLOAD_ERROR_3'),
                4 => Text::_('FIE_FORMEA_UPLOAD_ERROR_4'),
                6 => Text::_('FIE_FORMEA_UPLOAD_ERROR_6'),
                7 => Text::_('FIE_FORMEA_UPLOAD_ERROR_7'),
                8 => Text::_('FIE_FORMEA_UPLOAD_ERROR_8'),
            );

            return $phpFileUploadErrors;
        }
    }
