<?php

namespace Mnv\Core\Filesystem;

/**
 * Class FilesystemManager
 * @package Mnv\Core\Filesystem
 */
class FilesystemManager extends Filesystem
{

    /** Images */
    public array $ext_img = array( 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp' );
    public array $ext_copy_img = array( 'svg', 'ico' );

    /** Files */
    public array $ext_file = array( 'doc', 'docx', 'rtf', 'pdf', 'xls', 'xlsx', 'txt', 'csv', 'ppt', 'pptx', 'epub');

    /** Video */
    public array $ext_video = array( 'mov', 'mpeg', 'm4v', 'mp4', 'avi', 'mpg', 'wma', "webm" );

    /** Audio */
    public array $ext_music = array( 'mp3', 'mpga', 'm4a', 'ac3', 'aiff', 'mid', 'ogg', 'wav' );

    /** Archives */
    public array $ext_misc  = array( 'zip', 'rar', 'gz', 'tar', 'dmg' );

    /** @var string[] */
    public static $_hidden_image_folders = array('admin', 'large', 'medium', 'small');

    /** @var string[] */
    public static $_hidden_folders = array('vendor', 'large', 'medium', 'small');

    /** @var string[] */
    private array $sizes = array('large', 'medium', 'small');

    /** @var array  */
    public $response = [];

    /**
     * FileManager constructor.
     * @param string|null $path
     */
    public function __construct(string $directory = null, string $path = null)
    {

        $this->ensureDirectoryExists(GLOBAL_ROOT . $directory . DIRECTORY_SEPARATOR . $path);

        $this->realPath = realpath(GLOBAL_ROOT . $directory . DIRECTORY_SEPARATOR . $path) . DIRECTORY_SEPARATOR;
        if (strpos($this->realPath, GLOBAL_ROOT . $directory . DIRECTORY_SEPARATOR) === false) {
            $this->realPath = GLOBAL_ROOT . $directory . DIRECTORY_SEPARATOR;
        }

        $this->path = str_replace(GLOBAL_ROOT . $directory . DIRECTORY_SEPARATOR, '', $this->realPath);
    }

    /**
     * Получить все папки по заданному пути
     * @param array $hidden
     * @param bool|false $isSize
     * @return array
     */
    public function getDirectories(array $hidden, bool $isSize = false): array
    {
        $list = [];
        $size = 0;
        $directories = $this->directories($this->realPath);
        foreach ($directories as $directory) {
            $directoryBaseName = $this->basename($directory);
            $directoryName = $this->name($directory);
            $directoryDirName = $this->dirname($directory);
            if (!in_array($directoryName, $hidden)) {
                if ($isSize) list($size, $files_count, $folders_count) = $this->folder_info($directory);
                $list[] = [
                    'is_dir' => true,
                    'dirname'   => $directoryDirName,
                    'path'   => $directoryBaseName,
                    'name'   => $directoryName,
                    'mtime'  => is_writable($directory) ? $this->lastModified($directory) : '',
                    'size'   => $this->formattedFileSize($size),
//                    'size'  => $size,
                ];
            }
        }

        return $list;
    }

    /**
     * Список файлов
     *
     * @param array|null $where
     * @param string|null $query
     * @param string|null $filters
     * @param string|null $type
     * @param int $managerId
     * @param int $limit
     * @param int $page
     * @return array|mixed
     */
    public function all(?array $where, ?string $query, ?string $filters, ?string $type, int $managerId, int $limit, int $page)
    {

        $list = array();

        if (!empty($type)) {
            if ($type == 'mine') {
                $where['addedBy'] = $managerId;
            } else {
                connect()->where('mime_type', $type);
            }
        }
        if (!empty($query)) connect()->like('fileName', "%$query%");
        if (!empty($filters)) {
            if ($filters == 'date') connect()->orderBy('addedOn ASC');
            if ($filters == 'size') connect()->orderBy('size ASC');
            if ($filters == 'name') connect()->orderBy('fileName ASC');
        } else {
            connect()->orderBy('fileId DESC');
        }

        $lists = connect('files')->where($where)->pagination($limit, $page)->getAll('array');
        if ($lists) {
            foreach ($lists as $k => $file) {
                $extension = $this->extension($this->realPath . $file['fileName']);
                $list['files'][$k] = [
                    'is_dir'    => false,
                    'fileId'    => $file['fileId'],
                    'fileName'  => $file['fileName'],
//                    'size'      => $file['size'],
                    'size'      => $this->formattedFileSize($file['size']),
                    'mtime'     => is_writable($this->realPath . $file['fileName']) ?  $this->lastModified($this->realPath . $file['fileName']) : '',
                    'icon'      => GLOBAL_URL . '/admin/assets/ico/' . strtolower($extension) . '.svg',
                    'original'  => GLOBAL_URL . $file['path'] . $file['fileName']
                ];

                /** Video */
                if (in_array(strtolower($extension), $this->ext_video)) {
                    $list['files'][$k]['class_ext'] = 4;
                }
                /** Images */
                elseif (in_array(strtolower($extension), $this->ext_img)) {
                    $list['files'][$k]['class_ext'] = 2;
                }
                /** SVG */
                elseif (in_array(strtolower($extension), $this->ext_copy_img)) {
                    $list['files'][$k]['class_ext'] = 2;
                }
                /** Audio */
                elseif (in_array(strtolower($extension), $this->ext_music)) {
                    $list['files'][$k]['class_ext'] = 5;
                }
                /** Archives */
                elseif (in_array(strtolower($extension), $this->ext_misc)) {
                    $list['files'][$k]['class_ext'] = 3;
                } else {
                    $list['files'][$k]['class_ext'] = 1;
                }
            }

            return $list['files'];
        }

        return $list;
    }

    public function getTotalPage(?array $where, ?string $query, ?string $filters, ?string $type, int $managerId, int $limit, int $page)
    {
        if (!empty($type)) {
            if ($type == 'mine') {
                $where['addedBy'] = $managerId;
            }
        }
        if (!empty($query)) connect()->like('fileName', "%$query%");
        if (!empty($filters)) {
            if ($filters == 'date') connect()->orderBy('addedOn ASC');
            if ($filters == 'size') connect()->orderBy('size ASC');
            if ($filters == 'name') connect()->orderBy('fileName ASC');
        } else {
            connect()->orderBy('fileId DESC');
        }

        $list = connect('files')->count('*', 'count')->where($where)->get('array');

        if ($list['count'] > 0) {
            $pagination = getPageNums($list['count'], $page, $limit, 0, 4, 4, 9, null, false);
            unset($pagination['pages'],$pagination['lastPage'],$pagination['nextPage'],$pagination['firstPage'],$pagination['previousPage'],$pagination['startIteration']);

        } else {
            $pagination['currentPage'] = 1;
            $pagination['endIteration'] = 0;
            $pagination['totalItems'] = 0;
            $pagination['totalPages'] = 0;
        }

        return $pagination;
    }
    /**
     * Получение файла
     *
     * @param int $fileId
     * @return array
     */
    public function read(int $fileId): array
    {
        $list = array();
        if ($file = connect('files')->where('fileId', $fileId)->get('array')) {
            $extension = $this->extension($this->realPath . $file['fileName']);
            $list['fileId']     = $file['fileId'];
            $list['extension']  = $extension; // нужно для видео файлов
            $list['fileName']   = $file['fileName'];
            $list['size']       = $this->formattedFileSize($file['size']);
            $list['url']        = $file['path'] . $file['fileName'];
            $list['icon']       = GLOBAL_URL.'/admin/assets/ico/' . $extension . '.svg';

            if (in_array($extension, $this->ext_video)) { /** Video */
                $list['class_ext'] = 4;
                $list['type'] = 'video';
            } elseif (in_array($extension, $this->ext_img)) { /** Image */
                $list['class_ext'] = 2;
                $list['type'] = 'image';
            } elseif (in_array($extension, $this->ext_copy_img)) { /** SVG */
                $list['class_ext'] = 2;
                $list['type'] = 'svg';
            } elseif (in_array($extension, $this->ext_music)) { /** Audio */
                $list['class_ext'] = 5;
                $list['type'] = 'audio';
            } elseif (in_array($extension, $this->ext_misc)) { /** Archive zip, rar */
                $list['class_ext']  = 3;
                $list['type']  = 'archive';
            } else {
                $list['class_ext']  = 1;
                $list['original']   = $this->realPath . $file['fileName'];
            }
        }

        return $list;
    }


    /**
     * Определение размера каталога / Determine directory size
     * determineDirectorySize
     *
     * @param string $path
     * @return array
     * folder_info
     */
    private function folder_info(string $path): array
    {
        $total_size = 0;
        $files_count = 0;
        $folders_count = 0;

        if ($this->exists( $path)) {
            $directories = $this->directories($path);
            foreach ($directories as $directory) {
                if (!in_array($this->name($directory), self::$_hidden_image_folders)) {
                    list($size) = $this->folder_info($directory);
                    $total_size += $size;
                    $folders_count ++;
                }
            }
            $files = $this->files($path, false);
            foreach ($files as $file) {
                $size = $this->size($file->getRealPath());
                $total_size += $size;
                $files_count++;
            }
        }

        return array($total_size, $files_count, $folders_count);
    }

    /**
     * Удаление файла / файлов
     *
     * @param $fileIds
     * @return bool
     */
    public function deleteFiles($fileIds): bool
    {
        if ($files = connect('files')->in('fileId', $fileIds)->getAll()) {
            foreach ($files as $file) {
                if ($this->exists(GLOBAL_ROOT . $file->path . $file->fileName)) {
                    $this->delete(GLOBAL_ROOT . $file->path . $file->fileName);
                }
                foreach ($this->sizes as $size) {
                    if ($this->exists(GLOBAL_ROOT . $file->path . $size . '/' . $file->fileName)) {
                        $this->delete(GLOBAL_ROOT . $file->path . $size . '/' . $file->fileName);
                    }
                }

                connect('files')->where('fileId', $file->fileId)->delete();
            }
            return true;
        }

        return false;
    }

    /**
     * Удаление всех файлов с указаной директорией
     *
     * @param string $directory
     * @return bool
     */
    public function deleteAllFilesThisDirectory(string $directory): bool
    {
        if ($files = connect('files')->where('directory', $directory)->getAll()) {
            foreach ($files as $file) {
                connect('files')->where('fileId', $file->fileId)->delete();
            }

            return true;
        }

        return false;
    }

}