<?php

namespace Meibuyu\Common\UploadOss;

use Hyperf\Contract\ConfigInterface;
use League\Flysystem\Filesystem;
use Hyperf\Filesystem\FilesystemFactory;
use Hyperf\HttpMessage\Upload\UploadedFile;
use League\Flysystem\FileExistsException;
use Meibuyu\Common\Exceptions\HttpResponseException;
use Psr\Container\ContainerInterface;

class UploadOssService
{

    /**
     * @var FilesystemFactory
     */
    private $factory;

    /**
     * @var ConfigInterface
     */
    private $config;

    /**
     * @var string
     */
    private $urlPrefix;

    /**
     * @var string
     */
    private $appDev;

    /**
     * @var string
     */
    private $appName;

    /**
     * 是否自动保存数据库
     * @var bool
     */
    private $autoSaveDataBase = true;

    public static $options = [
        'maxSize' => 10 * 1024 * 1024, // 文件大小,10M
        'mime' => ['jpeg', 'png', 'gif', 'jpg', 'svg', 'txt', 'pdf', 'xlsx', 'xls', 'doc', 'docx', 'rar', 'zip', 'csv'], // 允许上传的文件类型
    ];

    public function __construct(ContainerInterface $container)
    {
        $this->config = $container->get(ConfigInterface::class);
        $this->factory = $container->get(FilesystemFactory::class);
        $ossConfig = $this->config->get('file.storage.oss');
        $this->urlPrefix = 'https://' . $ossConfig['bucket'] . '.' . $ossConfig['endpoint'] . '/';
        $this->appDev = $this->config->get('app_env');
        $this->appName = $this->config->get('app_name');
    }

    /**
     * 设置是否自动保存记录到数据库
     * @param bool $bool
     * @author chentianyu
     */
    public function setAutoSaveDataBase(bool $bool)
    {
        $this->autoSaveDataBase = $bool;
    }

    /**
     * 上传图片
     * @param \Hyperf\HttpMessage\Upload\UploadedFile $image
     * @param string $module
     * @return array|string
     * @throws \Meibuyu\Common\Exceptions\HttpResponseException
     * @author chentianyu
     */
    public function uploadImage(UploadedFile $image, string $module, $userId, $uniqueFileName = true)
    {
        $ext = $image->getExtension();
        $clientFilename = $image->getClientFilename();
        $fileName = $uniqueFileName ? ($this->genUniqueFileName() . '.' . $ext) : $clientFilename;
        $options = ['mime' => ['jpeg', 'png', 'gif', 'jpg', 'svg']];
        $filePath = 'oss2/' . $this->appDev . "/" . $this->appName . "/$module/images/" . today() . "/$userId/" . $fileName;
        $this->upload($image, $filePath, $options);
        if($this->autoSaveDataBase){
            $model = new FileModel();
            $model = $model->newInstance([
                'type'  => 'image',
                'module'  => $module,
                'user_id' => $userId,
                'source_name' => $clientFilename,
                'name' => $fileName,
                'path' => $this->urlPrefix . $filePath,
                'ext'  => $ext,
                'size' => num_2_file_size($image->getSize()),
            ]);
            $model->save();
            return $model->toArray();
        }else{
            return $this->urlPrefix . $filePath;
        }

    }

    /**
     * 上传文件
     * @param \Hyperf\HttpMessage\Upload\UploadedFile $image
     * @param string $module
     * @return array|string
     * @throws \Meibuyu\Common\Exceptions\HttpResponseException
     * @author chentianyu
     */
    public function uploadFile(UploadedFile $file, string $module, $userId, $uniqueFileName = true, array $options = [])
    {
        $ext = $file->getExtension();
        $clientFilename = $file->getClientFilename();
        $fileName = $uniqueFileName ? ($this->genUniqueFileName() . '.' . $ext) : $clientFilename;
        $filePath = 'oss2/' . $this->appDev . "/" . $this->appName . "/$module/files/" . today() . "/$userId/" . $fileName;
        $this->upload($file, $filePath, $options);
        if($this->autoSaveDataBase){
            $model = new FileModel();
            $model = $model->newInstance([
                'type'  => 'file',
                'module'  => $module,
                'user_id' => $userId,
                'source_name' => $clientFilename,
                'name' => $fileName,
                'path' => $this->urlPrefix . $filePath,
                'ext'  => $ext,
                'size' => num_2_file_size($file->getSize()),
            ]);
            $model->save();
            return $model->toArray();
        }else{
            return $this->urlPrefix . $filePath;
        }

    }

    /**
     * @param \Hyperf\HttpMessage\Upload\UploadedFile $file
     * @param $filePath
     * @param array $options
     * @return bool
     * @throws \Meibuyu\Common\Exceptions\HttpResponseException
     * @author chentianyu
     */
    public function upload(UploadedFile $file, string $filePath, array $options = [])
    {
        if ($file->isValid()) {
            $options = array_merge(self::$options, $options);
            $extension = strtolower($file->getExtension());
            // 通过扩展名判断类型
            if (!in_array($extension, $options['mime'])) {
                throw new HttpResponseException('文件类型不支持,目前只支持' . implode(',', $options['mime']));
            }
            // 判断文件大小
            if ($file->getSize() > $options['maxSize']) {
                throw new HttpResponseException('文件超出系统规定的大小,最大不能超过' . num_2_file_size($options['maxSize']));
            }
            try {
                $oss = $this->factory->get('oss');
                $stream = fopen($file->getRealPath(), 'r+');
                $res = $oss->writeStream($filePath, $stream);
                is_resource($stream) && fclose($stream);
                return $res;
            } catch (FileExistsException $e) {
                throw new HttpResponseException($e->getMessage());
            }
        } else {
            throw new HttpResponseException('文件无效');
        }
    }

    /**
     * 上传本地文件到oss
     * @param string $localFilePath
     * @param string $ossFilePath 枚举key
     * @param bool $fixedDir 使用oss固定目录
     * @return mixed
     * @throws HttpResponseException
     * @author Liu lu
     * date 2023-02-09
     */
    public function uploadLocalFile(string $localFilePath,  string $ossFilePath,$fixedDir=false)
    {
        $extension = pathinfo(parse_url($localFilePath,PHP_URL_PATH),PATHINFO_EXTENSION);
        if($fixedDir){
            $ossFilePath      = 'oss2/'.env('APP_ENV').'/'.env('APP_NAME') ."/{$ossFilePath}/". md5($localFilePath).'.'.$extension;
        }else{
            $fileName = $this->genUniqueFileName() . '.' . $extension;
            $ossFilePath      = 'oss2/'. $this->appDev .'/'. $this->appName ."/{$ossFilePath}/". today() .'/'. $fileName;
        }

        try {
            $oss = $this->factory->get('oss');
            $stream = fopen($localFilePath, 'r+');
            $oss->writeStream($ossFilePath, $stream);
            is_resource($stream) && fclose($stream);
            return $this->urlPrefix . $ossFilePath;
        } catch (FileExistsException $e) {
            throw new HttpResponseException($e->getMessage());
        }
    }

    /**
     * 生成唯一文件名
     * @return string
     * @author chentianyu
     */
    public function genUniqueFileName()
    {
        return date('YmdHis') . uniqid();
    }

}