<?php

declare(strict_types=1);

/*
 * This file is part of eSales Media SinglereisenBundle
 *
 * (c) Benjamin Roth
 *
 * @license proprietary
 */

namespace vonRotenberg\MemberfilesBundle\Controller\Frontend\ContentElement;

use Contao\BackendTemplate;
use Contao\Config;
use Contao\ContentModel;
use Contao\Controller;
use Contao\CoreBundle\Controller\ContentElement\AbstractContentElementController;
use Contao\CoreBundle\ServiceAnnotation\ContentElement;
use Contao\Environment;
use Contao\File;
use Contao\FilesModel;
use Contao\FrontendUser;
use Contao\Image;
use Contao\Input;
use Contao\StringUtil;
use Contao\System;
use Contao\Template;
use Doctrine\DBAL\Connection;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\Translation\TranslatorInterface;
use vonRotenberg\MemberfilesBundle\Model\SecureDownloadsModel;

/**
 * @ContentElement(SecureDownloadsController::TYPE, category="files")
 */
class SecureDownloadsController extends AbstractContentElementController
{
    public const TYPE = 'secure_downloads';

    /** @var Connection */
    protected $db;

    protected $User;

    public function __construct(Connection $db)
    {
        $this->db = $db;
        $this->User = FrontendUser::getInstance();
    }

    public function __invoke(Request $request, ContentModel $model, string $section, array $classes = null): Response
    {
        if (System::getContainer()->get('contao.routing.scope_matcher')->isBackendRequest($request)) {
            return $this->getBackendWildcard($model);
        }
        return parent::__invoke($request, $model, $section, $classes); // TODO: Change the autogenerated stub
    }


    protected function getResponse(Template $template, ContentModel $model, Request $request): Response
    {
        // The module is only accessible for authenticated members
        if (!System::getContainer()->get('contao.security.token_checker')->hasFrontendUser())
        {
            return new Response('',403);
        }

        // Handle file requests
        if (
            ($path = Input::get('file', true)) !== null
            && ($File = FilesModel::findByPath($path)) !== null
            && ($SecFile = $SecFile = SecureDownloadsModel::findBy(["uuid = ?"],[$File->uuid])) !== null
        )
        {
            if ($SecFile->pid == $this->User->id)
            {
                $this->db->update('tl_member_secureDownloads', ['opened' => time()], ['id' => $SecFile->id]);
                Controller::sendFileToBrowser($path);
            } else {
                return new Response('',403);
            }
        }

        // Get member files for authenticated user
        $strLocale = $request->getLocale();
        $allowedDownload = StringUtil::trimsplit(',', strtolower(\Config::get('allowedDownload')));
        $UserFiles = $this->db->executeQuery("SELECT uuid FROM tl_member_secureDownloads WHERE pid = ?",[$this->User->id]);

        // Return if there are no files
        if ($UserFiles->rowCount() < 1)
        {
            return new Response();
        }

        $arrUuid = $UserFiles->fetchFirstColumn();

        if (($objFiles = FilesModel::findMultipleByUuids($arrUuid)) === null)
        {
            return new Response();
        }

        while ($objFiles->next())
        {
            // Continue if the files has been processed or does not exist
            if (isset($files[$objFiles->path]) || !file_exists(TL_ROOT . '/' . $objFiles->path))
            {
                continue;
            }

            // Single files
            $SecureFile = SecureDownloadsModel::findBy(["uuid = ?"],[$objFiles->uuid]);
            if ($objFiles->type == 'file')
            {
                $File = new File($objFiles->path);

                if (!in_array($File->extension, $allowedDownload) || preg_match('/^meta(_[a-z]{2})?\.txt$/', $File->basename))
                {
                    continue;
                }

                $arrMeta = $objFiles->current()->getMetaData($strLocale);

                if (empty($arrMeta))
                {
                    if ($model->metaIgnore)
                    {
                        continue;
                    }
                    elseif (($arrMeta = $objFiles->current()->getMetaData('en')) === null || $arrMeta === null)
                    {
                        $arrMeta = [];
                    }
                }

                // Use the file name as title if none is given
                if (empty($arrMeta['title']))
                {
                    $arrMeta['title'] = StringUtil::specialchars($File->basename);
                }

                $strHref = Environment::get('request');

                // Remove an existing file parameter (see #5683)
                if (preg_match('/(&(amp;)?|\?)file=/', $strHref))
                {
                    $strHref = preg_replace('/(&(amp;)?|\?)file=[^&]+/', '', $strHref);
                }

                $strHref .= ((Config::get('disableAlias') || strpos($strHref, '?') !== false) ? '&amp;' : '?') . 'file=' . System::urlEncode($objFiles->path);

                // Add the image
                $files[$objFiles->path] = array
                (
                    'id'        => $objFiles->id,
                    'uuid'      => $objFiles->uuid,
                    'name'      => $File->basename,
                    'title'     => StringUtil::specialchars(sprintf($GLOBALS['TL_LANG']['MSC']['download'], $File->basename)),
                    'link'      => $arrMeta['title'] ?? '',
                    'caption'   => $arrMeta['caption'] ?? '',
                    'href'      => $strHref,
                    'filesize'  => System::getReadableSize($File->filesize, 1),
                    'icon'      => Image::getPath($File->icon),
                    'mime'      => $File->mime,
                    'meta'      => $arrMeta,
                    'extension' => $File->extension,
                    'path'      => $File->dirname,
                    'mtime'     => $File->mtime,
                    'opened'      => ($SecureFile !== null ? $SecureFile->opened : 0)
                );

                $auxDate[] = $File->mtime;
            }

            // Folders
            else
            {
                $objSubfiles = FilesModel::findByPid($objFiles->uuid);

                if ($objSubfiles === null)
                {
                    continue;
                }

                while ($objSubfiles->next())
                {
                    // Skip subfolders
                    if ($objSubfiles->type == 'folder')
                    {
                        continue;
                    }

                    $File = new File($objSubfiles->path);

                    if (!in_array($File->extension, $allowedDownload) || preg_match('/^meta(_[a-z]{2})?\.txt$/', $File->basename))
                    {
                        continue;
                    }

                    $arrMeta = $objSubfiles->current()->getMetaData($strLocale);

                    if (empty($arrMeta))
                    {
                        if ($model->metaIgnore)
                        {
                            continue;
                        }
                        elseif (($arrMeta = $objSubfiles->current()->getMetaData('en')) === null || $arrMeta === null)
                        {
                            $arrMeta = [];
                        }
                    }

                    // Use the file name as title if none is given
                    if (empty($arrMeta['title']))
                    {
                        $arrMeta['title'] = StringUtil::specialchars($File->basename);
                    }

                    $strHref = Environment::get('request');

                    // Remove an existing file parameter (see #5683)
                    if (preg_match('/(&(amp;)?|\?)file=/', $strHref))
                    {
                        $strHref = preg_replace('/(&(amp;)?|\?)file=[^&]+/', '', $strHref);
                    }

                    $strHref .= ((Config::get('disableAlias') || strpos($strHref, '?') !== false) ? '&amp;' : '?') . 'file=' . System::urlEncode($objSubfiles->path);

                    // Add the image
                    $files[$objSubfiles->path] = array
                    (
                        'id'        => $objSubfiles->id,
                        'uuid'      => $objSubfiles->uuid,
                        'name'      => $File->basename,
                        'title'     => StringUtil::specialchars(sprintf($GLOBALS['TL_LANG']['MSC']['download'], $File->basename)),
                        'link'      => $arrMeta['title'] ?? '',
                        'caption'   => $arrMeta['caption'] ?? '',
                        'href'      => $strHref,
                        'filesize'  => System::getReadableSize($File->filesize, 1),
                        'icon'      => Image::getPath($File->icon),
                        'mime'      => $File->mime,
                        'meta'      => $arrMeta,
                        'extension' => $File->extension,
                        'path'      => $File->dirname,
                        'opened'      => ($SecureFile !== null ? $SecureFile->opened : 0)
                    );

                    $auxDate[] = $File->mtime;
                }
            }
        }

        // Sort array
        switch ($model->sortBy)
        {
            default:
            case 'name_asc':
                uksort($files, 'basename_natcasecmp');
                break;

            case 'name_desc':
                uksort($files, 'basename_natcasercmp');
                break;

            case 'date_asc':
                array_multisort($files, SORT_NUMERIC, $auxDate, SORT_ASC);
                break;

            case 'date_desc':
                array_multisort($files, SORT_NUMERIC, $auxDate, SORT_DESC);
                break;

            case 'random':
                shuffle($files);
                break;
        }

        $template->files = array_values($files);

        return $template->getResponse();
    }

    protected function getBackendWildcard(ContentModel $element): Response
    {
        $href = $this->container->get('router')->generate(
            'contao_backend',
            ['do' => 'themes', 'table' => 'tl_module', 'act' => 'edit', 'id' => $element->id]
        );

        $name = $this->container->get('translator')->trans('FMD.'.$this->getType().'.0', [], 'contao_modules');

        $template = new BackendTemplate('be_wildcard');
        $template->wildcard = '### '.strtoupper($name).' ###';
        $template->id = $element->id;
        $template->link = $element->name;
        $template->href = $href;

        return new Response($template->parse());
    }

    public static function getSubscribedServices(): array
    {
        $services = parent::getSubscribedServices();

        $services['translator'] = TranslatorInterface::class;

        return $services;
    }
}