<?php

use Core\Db;

/**
 * Единая функция для заливки файлов на сервер.
 *
 * @author    Ivor Barhansky <me@lopar.space>
 * @version   1
 */
class Uploader
{
    public static string $error;
    private array $width = ['min' => 0, 'max' => 0];
    private array $height = ['min' => 0, 'max' => 0];
    private int $maxFileSizeMb;
    private string $savePath;
    private string $extensions = 'jpg|png|jpeg|gif';
    private array $extMatches = [];
    private array $file;
    private string $customName;

    public function __construct($name)
    {
        if (!isset($_FILES[$name])) {
            return;
        }
        $this->file = $_FILES[$name];
    }

    /**
     * @param string $customName
     */
    public function setCustomName(string $customName): void
    {
        $this->customName = $customName;
    }

    /**
     * @param string $path путь от корня до конечной папки без открывающего слеша.
     * @return void
     */
    public function setSavePath(string $path)
    {
        $this->savePath = $_SERVER['DOCUMENT_ROOT'] . '/' . $path;
    }

    /**
     * @param string|array $ext
     * @return void
     */
    public function setExtentions($ext)
    {
        if (is_array($ext)) {
            $arr = $ext;
        } else {
            $arr[] = $ext;
        }
        if (!$arr) {
            return;
        }
        $this->extensions = implode('|', $arr);
    }

    /**
     * @param int $width
     * @param int $height
     * @return void
     */
    public function setDimensions(int $width, int $height)
    {
        $this->setWidth($width);
        $this->setHeight($height);
    }

    /**
     * @param int $max
     * @param int|null $min
     * @return void
     */
    public function setWidth(int $max, ?int $min = null)
    {
        $this->width['min'] = is_null($min) ? $max : $min;
        $this->width['max'] = $max;
    }

    /**
     * @param int $max
     * @param int|null $min
     * @return void
     */
    public function setHeight(int $max, ?int $min = null)
    {
        $this->height['min'] = is_null($min) ? $max : $min;
        $this->height['max'] = $max;
    }

    public function saveimg()
    {
        return $this->hasNormalFilePath() &&
        $this->hasNormalDimensions() &&
        $this->hasNormalFileSize() &&
        $this->hasNormalType() ? $this->upload() : false;
    }

    private function hasNormalFilePath(): bool
    {
        if (!$this->savePath || !is_dir($this->savePath)) {
            self::$error = 'Ошибка загрузки: нет такой папки.';
            return false;
        }
        return true;
    }

    private function hasNormalDimensions(): bool
    {
        [$width, $height] = getimagesize($this->file['tmp_name']);
        if (!$width || !$height) {
            self::$error = 'Не подтянулись размеры файла.';
            return false;
        }
        if (
            ($width < $this->width['min'] || $width > $this->width['max']) ||
            ($height < $this->height['min'] || $height > $this->height['max'])
        ) {
            self::$error = 'Требования к размеру: ';
            if ($this->width['min'] !== $this->width['max'] || $this->height['min'] !== $this->height['max']) {
                self::$error .= "от [{$this->width['min']} x {$this->height['min']}] до ";
            }
            self::$error .= "[{$this->width['max']} x {$this->height['max']}].";
            self::$error .= " Текущий размер [$width x $height]";
            return false;
        }
        return true;
    }

    private function hasNormalFileSize(): bool
    {
        if (!$this->maxFileSizeMb) {
            $this->setMaxFileSize(2);
        }
        if ($this->file['size'] > $this->maxFileSizeMb * (1024 * 1024) || $this->file['size'] <= 0) {
            self::$error = 'Неверный размер файла. Максимальный размер файла ' . $this->maxFileSizeMb . ' МБ';
            return false;
        }
        return true;
    }

    /**
     * @param $megabytes
     * @return void
     */
    public function setMaxFileSize($megabytes)
    {
        $this->maxFileSizeMb = $megabytes;
    }

    private function hasNormalType(): bool
    {
        if (
            !preg_match('/\.(' . $this->extensions . ')$/i', $this->file['name'], $this->extMatches) ||
            !preg_match('/image/i', $this->file['type'])
        ) {
            self::$error = 'Неверный тип файла. Допустимые типы : ' . $this->extensions;
            return false;
        }
        return true;
    }

    private function upload()
    {
        $this->extMatches[1] = strtolower($this->extMatches[1]);
        $fn = uniqid('f_', true) . '.' . $this->extMatches[1];
        $fn2 = uniqid('f_', true) . '.gif';
        if ($this->customName) {
            $fn = $this->customName . '.' . pathinfo($this->file['name'], PATHINFO_EXTENSION);
            $fn2 = $this->customName;
        }
        if (!move_uploaded_file($this->file['tmp_name'], $this->savePath . $fn)) {
            self::$error = 'Ошибка загрузки файла';
            return false;
        }
        var_dump([$fn2, $fn, $this->savePath . $fn]);
        return [$fn2, $fn, $this->savePath . $fn];
    }

    public function saveToDb()
    {
        return $this->hasNormalDimensions() &&
        $this->hasNormalFileSize() &&
        $this->hasNormalType() ? $this->uploadToDatabase() : false;
    }

    private function uploadToDatabase(): int
    {
        $id = time();
        Db::sql('insert into images (mime_type, img, id) VALUES (?,?,?)', [$this->file['type'], file_get_contents($this->file['tmp_name']), $id]);
        return $id;
    }
}