<?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\Administrator\Controller;

defined('_JEXEC') or die;

use Balbooa\Component\Forms\Administrator\Controller\Trait\HasSessionTokenCheck;
use Balbooa\Component\Forms\Administrator\Exceptions\AccessDeniedException;
use Balbooa\Component\Forms\Administrator\Exceptions\FileUploadException;
use Balbooa\Component\Forms\Administrator\Helper\AccessGuard;
use Balbooa\Component\Forms\Administrator\Helper\BaformsHelper;
use Balbooa\Component\Forms\Administrator\Helper\Filesystem\File;
use Balbooa\Component\Forms\Administrator\Helper\Filesystem\Folder;
use Balbooa\Component\Forms\Administrator\Model\UploaderModel;
use Joomla\CMS\MVC\Controller\FormController;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Response\JsonResponse;

class UploaderController extends FormController
{
    use HasSessionTokenCheck;
    
    public function moveTo()
    {
        AccessGuard::check('core.edit');
        $image = $this->input->get('ba_image', '', 'string');
        $folder = $this->input->get('ba_folder', '', 'string');
        /** @var UploaderModel $model */
        $model = $this->getModel();
        $file = realpath($model->getBaseFolder() . $image);
        $target = realpath($model->getBaseFolder() . $folder);
        if (!$target || !$file || !$model->isPathInsideBaseDirectory($file, true)) {
            throw new AccessDeniedException();
        }

        if (Folder::exists($file)) {
            $name = explode('/', $file);
            $name = end($name);
            Folder::move($file, $target.'/'.$name);
        } else if (File::exists($file)) {
            $name = basename($file);
            File::move($file, $target.'/'.$name);
        }        
        echo new JsonResponse(true, Text::_('SUCCESS_MOVED'));
        jexit();
    }

    public function moveTarget()
    {
        AccessGuard::check('core.edit');
        $ba_target = $this->input->get('ba_target', '', 'string');
        $ba_path = $this->input->get('ba_path', '', 'string');
        /** @var UploaderModel $model */
        $model = $this->getModel();
        $target = realpath($model->getBaseFolder() . $ba_target);
        $path = realpath($model->getBaseFolder() . $ba_path);
        if ($ba_path == $model->getBaseFolder()) {
            $path = realpath($model->getBaseFolder());
        }
        if (!$target || !$path || !$model->isPathInsideBaseDirectory($target, true)) {
            throw new AccessDeniedException();
        }
        $flag = $this->input->get('ba_flag', '', 'string');
        if (!(bool)$flag) {
            if (!empty($target)) {
                if (Folder::exists($target)) {
                    $name = explode('/', $target);
                    $name = end($name);
                    Folder::move($target, $path.'/'.$name);
                } else if (File::exists($target)) {
                    $name = basename($target);
                    File::move($target, $path.'/'.$name);
                }
            }
        } else {
            $target = explode(';', $target);
            foreach ($target as $key => $item) {
                if (!empty($item)) {
                    if (Folder::exists($item)) {
                        $name = explode('/', $item);
                        $name = end($name);
                        Folder::move($item, $path.'/'.$name);
                    } else if (File::exists($item)) {
                        $name = basename($item);
                        File::move($item, $path.'/'.$name);
                    }
                }
            }
        }
        echo new JsonResponse($path.'/'.$name, Text::_('SUCCESS_MOVED'));
        jexit();
    }

    public function renameTarget()
    {
        AccessGuard::check('core.edit');
        $ba_target = $this->input->get('ba_target', '', 'string');
        /** @var UploaderModel $model */
        $model = $this->getModel();
        $realPath = realpath($model->getBaseFolder() . $ba_target);
        if (!$realPath || !$model->isPathInsideBaseDirectory($realPath, true)) {
            throw new AccessDeniedException();
        }
        $name = $this->input->get('ba_name', '', 'string');
        $name = str_replace(' ', '-', $name);
        $dir = explode('/', $realPath);
        $n = count($dir) - 1;
        unset($dir[$n]);
        $dir = implode('/', $dir);
        if (!empty($realPath)) {
            if (Folder::exists($realPath)) {
                Folder::move($realPath, $dir.'/'.$name);
            } else if (File::exists($realPath)) {
                $ext = File::getExt($realPath);
                $name .= '.'.$ext;
                File::move($realPath, $dir.'/'.$name);
            }
        }
        echo new JsonResponse($dir.'/'.$name, Text::_('SUCCESS_RENAME'));
        jexit();
    }

    public function deleteTarget()
    {
        AccessGuard::check('core.delete');
        $ba_target = $this->input->get('ba_target', '', 'string');
        /** @var UploaderModel $model */
        $model = $this->getModel();
        $realPath = realpath($model->getBaseFolder() . $ba_target);
        if (!$realPath || !$model->isPathInsideBaseDirectory($realPath, true)) {
            throw new AccessDeniedException();
        }

        $result = Text::_('COM_BAFORMS_N_ITEMS_DELETED');
        if (Folder::exists($realPath)) {
            Folder::delete($realPath);
        } else if (File::exists($realPath)) {
            File::delete($realPath);
        }
        echo new JsonResponse(true, $result);
        jexit();
    }

    public function addFolder()
    {
        AccessGuard::check('core.create');
        $location = $this->getDir();
        $dir = $location[0];
        if (!$dir) {
            throw new AccessDeniedException();
        }
        $nfolder = $this->input->get('new-folder', '', 'string');
        $nfolder = str_replace(' ', '-', $nfolder);
        if (Folder::create($dir.'/'.$nfolder)) {
            $result = Text::_('FOLDER_IS_CREATED');
        } else {
            $result = Text::_('FOLDER_IS_NOT_CREATED');
        }
        echo '<input type="hidden" id="ba-message-data" value="'.$result.'">';
        ?>
            <script type="text/javascript">
                var msg = document.getElementById("ba-message-data").value;
                window.parent.postMessage(msg, "*");
            </script>

        <?php
        exit;
    }
    
    public function getDir()
    {
        AccessGuard::check('core.edit');
        $redirect = 'index.php?option=com_baforms&view=uploader&tmpl=component';
        $dir = JPATH_ROOT. '/'.BaformsHelper::$image_path;
        $folder = $this->input->get('current-dir', '', 'string');
        if (!empty($folder)) {
            $dir = $folder;
            $redirect .= '&folder=' .$dir;
        }

        return [realpath($dir), $redirect];
        
    }
    
    public function delete()
    {
        AccessGuard::check('core.delete');
        $location = $this->getDir();
        $dir = $location[0];
        $items = $this->input->get('ba-rm', '', 'array');
        $result = Text::_('COM_BAFORMS_N_ITEMS_DELETED');
        /** @var UploaderModel $model */
        $model = $this->getModel();
        foreach ($items as $item) {
            $realPath = realpath($dir.'/'.$item);
            if (!$realPath || !$model->isPathInsideBaseDirectory($realPath, true)) {
                throw new AccessDeniedException();
            }

            if (Folder::exists($realPath)) {
                Folder::delete($realPath);
            }
            if (File::exists($realPath)) {
                File::delete($realPath);
            }
        }
        echo '<input type="hidden" id="ba-message-data" value="'.$result.'">';
        ?>
            <script type="text/javascript">
                var msg = document.getElementById("ba-message-data").value;
                window.parent.postMessage(msg, "*");
            </script>

        <?php
        exit;
    }

    public function uploadAjax()
    {
        AccessGuard::check('core.create');
        $folder = $this->input->get('folder', '', 'string');
        /** @var UploaderModel $model */
        $model = $this->getModel();

        if (empty($folder)) {
            $folder = $model->getBaseFolder();
        }
        $realFolder = realpath($folder);
        if (!$model->isPathInsideBaseDirectory($realFolder, true)) {
            throw new FileUploadException();
        }

        $file = $this->input->files->get('file', [], 'array');
        $types = $model->getFiletypes();
        if (!File::canUploadFile($file, $types)) {
            throw new FileUploadException();
        }


        $ext = strtolower(File::getExt($file['name']));
        $name = str_replace('.'.$ext, '', $file['name']);
        $filename = BaformsHelper::replace($name);
        $filename = File::makeSafe($filename.'.'.$ext);
        $name = str_replace('-', '', $filename);
        $name = str_replace($ext, '', $name);
        $name = str_replace('.', '', $name);
        if ($name == '') {
            $filename = date("Y-m-d-H-i-s").'.'.$ext;
        }
        File::upload($file['tmp_name'], $realFolder. '/' . $filename);


        $current = str_replace($model->getBaseFolder(), '', $realFolder);
        $url = Uri::root() . BaformsHelper::$image_path . $current;

        $image = new \stdClass;
        $image->name = $file;
        $image->path = $current.'/'.$file;
        $image->size = filesize($folder. '/'. $file);
        $image->ext = $ext;
        $image->url = $url. '/' .$file;
        echo json_encode($image);
        exit;
    }

    public function formUpload()
    {
        AccessGuard::check('core.create');
        $items = $this->input->files->get('files', '', 'array');
        /** @var UploaderModel $model */
        $model = $this->getModel();
        $types = $model->getFiletypes();

        foreach ($items as $file) {
            if (!File::canUploadFile($file, $types)) {
                throw new FileUploadException();
            }
        }

        $dir = $this->input->get('current_folder', '', 'string');
        if (empty($dir) || $dir == '/') {
            $dir = $model->getBaseFolder() . '/';
        }
        $realFolder = realpath($dir);
        if (!$model->isPathInsideBaseDirectory($realFolder, true)) {
            throw new FileUploadException();
        }

        $url = Uri::root() . BaformsHelper::$image_path;

        $current = str_replace(JPATH_ROOT . '/' . BaformsHelper::$image_path, '', $dir);
        $url .= $current;
        $images = [];

        foreach($items as $item) {
            $ext = strtolower(File::getExt($item['name']));
            $name = str_replace('.'.$ext, '', $item['name']);
            $file = BaformsHelper::replace($name);
            $file = File::makeSafe($file.'.'.$ext);
            $name = str_replace('-', '', $file);
            $name = str_replace($ext, '', $name);
            $name = str_replace('.', '', $name);
            if ($name == '') {
                $file = date("Y-m-d-H-i-s").'.'.$ext;
            }
            File::upload($item['tmp_name'], $dir. $file);
            $image = new \stdClass;
            $image->name = $file;
            $image->ext = $ext;
            $image->path = $current.'/'.$file;
            $image->size = filesize($dir. $file);
            $image->url = $url. '/' .$file;
            $images[] = $image;
        }
        $images = json_encode($images);
?>
    <script type="text/javascript">
        window.parent.uploadCallback(<?php echo $images; ?>);
    </script>
<?php
    exit();
    }

    public function showImage()
    {
        AccessGuard::check('core.edit');

        $image = $this->input->getVar('image', '', 'get', 'string');
        $file = JPATH_ROOT. '/'.BaformsHelper::$image_path . $image;
        $realPath = realpath($file);
        if (!$realPath || !file_exists($realPath)) {
            http_response_code(404);
            exit;
        }

        $ext = File::getExt($file);
        if (!$this->getModel()->isImage($ext)) {
            http_response_code(403);
            exit;
        }

        $imageCreate = $this->imageCreate($ext);
        $imageSave = $this->imageSave($ext);
        Header("Content-type: image/$ext");
        if (!$img = $imageCreate($file)) {
            $resource = fopen($file, "r");
            fpassthru($resource);
        } else {
            $width = imagesx($img);
            $height = imagesy($img);
            $ratio = $width / $height;
            if ($width > $height) {
                $w = 100;
                $h = round(100 / $ratio);
            } else {
                $h = 100;
                $w = round(100 * $ratio);
            }
            $out = imagecreatetruecolor($w, $h);
            if ($ext == 'png' || $ext == 'webp') {
                imagealphablending($out, false);
                imagesavealpha($out, true);
                $transparent = imagecolorallocatealpha($out, 255, 255, 255, 127);
                imagefilledrectangle($out, 0, 0, $w, $h, $transparent);
            }
            imagecopyresampled($out, $img, 0, 0, 0, 0, $w, $h, $width, $height);
            $imageSave($out);
            imagedestroy($img);
            imagedestroy($out);
        }
        exit;
    }

    public function imageSave($type): string
    {
        return match ($type) {
            'png' => 'imagepng',
            'gif' => 'imagegif',
            'webp' => 'imagewebp',
            default => 'imagejpeg',
        };
    }

    public function imageCreate($type): string
    {
        return match ($type) {
            'png' => 'imagecreatefrompng',
            'gif' => 'imagecreatefromgif',
            'webp' => 'imagecreatefromwebp',
            default => 'imagecreatefromjpeg',
        };
    }
}