<?php

namespace KupShop\ContentBundle\Util;

use KupShop\ComponentsBundle\Entity\Thumbnail;
use KupShop\ContentBundle\Entity\Image;
use KupShop\KupShopBundle\Context\LanguageContext;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Contexts;
use KupShop\KupShopBundle\Util\StringUtil;
use KupShop\KupShopBundle\Util\System\PathFinder;
use KupShop\KupShopBundle\Util\System\UrlFinder;
use Query\Operator;
use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext;

class ImageLocator
{
    /**
     * @var PathFinder
     */
    private $pathFinder;

    /** @var UrlFinder */
    protected $urlFinder;

    // Default settings
    private $default = [
        'crop' => true,
        'background' => false,
        'watermark' => false,
        'png' => false,
        'svg' => false,
        'upscale' => false,
        'quality' => null,
        'sharpen' => null,
        'contrast' => null,
    ];

    public function __construct(PathFinder $pathFinder)
    {
        $this->pathFinder = $pathFinder;
    }

    public function getConfig()
    {
        global $cfg;

        return $cfg['Photo'];
    }

    public function getThumbnailPath(Thumbnail $thumbnail, string $type, string $size): string
    {
        // TODO: Tady začni generovat cestu bez extension a asi teda i kvůli SEO šovinistům i s názevm souboru :-(
        // TODO: A ideálně nějakou custom URL, co se bude zpracovávat v PHP, ale bude na CDN cachovaná.
        $config = $this->getTypeConfig($type);

        $lang = null;
        if (!empty($config['lang'])) {
            $lang = Contexts::get(LanguageContext::class)->getActiveId();
        }

        return $this->getNewPath($thumbnail, $type, $size, $lang);
    }

    public function getThumbnailUrl(Thumbnail $thumbnail, string $type, string $size)
    {
        $path = $this->getThumbnailPath($thumbnail, $type, $size);

        if (isFunctionalTests()) {
            $version = '';
        } else {
            $version = is_numeric($thumbnail->version) ? $thumbnail->version : strtotime($thumbnail->version);
        }

        return $this->urlFinder->staticUrl("{$path}?{$version}");
    }

    public function getNewPath(Thumbnail $thumbnail, string $type, string $version, ?string $lang = null): string
    {
        $path = "photo/{$type}/{$thumbnail->id}/";
        $path .= empty($thumbnail->title) ? 'photo' : StringUtil::slugify($thumbnail->title);
        $path .= empty($version) ? '' : ".{$version}";
        $path .= empty($lang) ? '' : ".{$lang}";

        return $this->pathFinder->shopPath($path);
    }

    public function getPath($id, $type, $ext = 'jpg', $lang = null, ?string $version = null)
    {
        $config = $this->getConfig();

        if (!is_numeric($type)) {
            if (!isset($config['type_to_id'])) {
                $config['type_to_id'] = array_flip($config['id_to_type']);
            }

            $type = $config['type_to_id'][$type];
        }

        $subFolder = $id % 10;

        if ($lang) {
            $ext = "{$lang}.{$ext}";
        }

        $versionString = '';
        if ($version && $version !== \Photos::PHOTO_VERSION_DESKTOP && $version !== 'desktop') {
            $versionString = "_{$version}";
        }

        return $this->pathFinder->tmpPath("{$type}/{$subFolder}/{$id}_{$type}{$versionString}.{$ext}");
    }

    public function getTypeName($type)
    {
        $config = $this->getConfig();
        if (is_numeric($type)) {
            $type = getVal($type, $config['id_to_type'], $type);
        }

        if (!isset($config['types'][$type])) {
            throw new \UnexpectedValueException('Neznámý typ obrázku: '.$type);
        }

        return $type;
    }

    public function getTypeConfig(&$type)
    {
        $config = $this->getConfig();

        $type = $this->getTypeName($type);

        return array_merge($this->default, $config['default'], $config['types'][$type]);
    }

    public function getImageById(int $id): ?Image
    {
        $photo = sqlQueryBuilder()
            ->select('*')
            ->from('photos')
            ->where(Operator::equals(['id' => $id]))
            ->execute()->fetchAssociative();

        if (!$photo) {
            return null;
        }

        return $this->getImage($photo);
    }

    public function getImage(array $photo): Image
    {
        return (new Image())
            ->setId((int) $photo['id'])
            ->setVideoId($photo['id_video'] ?? null)
            ->setDescription($photo['descr'])
            ->setSource($photo['source'])
            ->setImageDesktop($photo['image_2'])
            ->setImageTablet($photo['image_tablet'])
            ->setImageMobile($photo['image_mobile'])
            ->setDate(!empty($photo['date']) ? new \DateTime($photo['date_update']) : null)
            ->setDateUpdated(new \DateTime($photo['date_update']))
            ->setData(json_decode($photo['data'] ?? '', true) ?: []);
    }

    public function getOldImageArray($id, $file, $folder, $type, $desc = '', ?int $dateUpdate = null, ?string $data = null): ?array
    {
        if (empty($id)) {
            return null;
        }

        $settings = $this->getTypeConfig($type);

        // All thumbnails now use `jpg` extension
        $ext = 'jpg';

        $lang = null;
        if (!empty($settings['lang'])) {
            $lang = Contexts::get(LanguageContext::class)->getActiveId();
        }

        $path_large = $this->getPath($id, 0, $ext, $lang);
        $path_thumbnail = $this->getPath($id, $type, $ext, $lang);

        $ret = [
            'id' => $id,
            'src' => &$path_thumbnail,
            'source' => &$path_thumbnail,
            'descr' => $desc,
            'width' => $settings['size'][0] ?? 0, // TODO: Revert, responsive types should not be accessed using getOldImageArray
            'height' => $settings['size'][1] ?? 0,
            'src_big' => &$path_large,
            'source_big' => &$path_large,
            'date_update' => $dateUpdate,
            'type' => $this->getTypeName($type),
        ];

        if ($data) {
            $data = json_decode($data, true);
            $ret = array_merge($data, $ret);
        }

        if (($dateUpdate ?? -1) > 0) {
            $time_thumbnail = $time_large = (isFunctionalTests()) ? '' : $dateUpdate;
        } else {
            if (isLocalDevelopment()) {
                $logger = ServiceContainer::getService('logger');
                $logger->error('getOldImageArray bez data poslední změny '.$type, array_merge($ret, ['exception' => new SilencedErrorContext(1, '', 0, debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 5), 1)]));
            }
            $time_thumbnail = $time_large = '';
        }

        $imageVersion = '';
        if (!isFunctionalTests()) {
            $imageVersion = '_'.(\Settings::getDefault()->image_version ?? '1');
        }

        $path_thumbnail .= "?{$time_thumbnail}{$imageVersion}";
        $path_large .= "?{$time_large}{$imageVersion}";

        $path_thumbnail = $this->urlFinder->staticUrl($path_thumbnail);
        $path_large = $this->urlFinder->staticUrl($path_large);

        return $ret;
    }

    public function clearThumbnails($image_id, $version = null)
    {
        foreach ($this->getConfig()['id_to_type'] as $id => $type) {
            foreach (glob($this->getPath($image_id, $id, '', null, $version).'*') as $filename) {
                @unlink($filename);
            }
        }

        return true;
    }

    /**
     * @required
     */
    public function setUrlFinder(UrlFinder $urlFinder): void
    {
        $this->urlFinder = $urlFinder;
    }
}
