<?php

namespace Application\Service\Extension\Uploader;



use Application\Service\Extension\Laminas;
use Application\Service\Extension\Uploader\adapter\Local;
use Application\Service\Extension\Uploader\adapter\Oss;
use League\Flysystem\FilesystemException;
use OSS\Core\OssException;
use phpDocumentor\Reflection\Types\Mixed;

/**
 * 图片上传器
 * 支持 OSS, 本地
 */
class ImageUploader
{
    /**
     * 上传驱动器
     * @var string
     */
    public string $driver;

    /**
     * 允许上传的类型
     * @var array
     */
    public array $allowExtensions;

    /**
     * 文件最大上传大小(KB)
     * @var int
     */
    public int $maxSize;

    /**
     * @var Image
     */
    public Image $file;

    /**
     * @var array
     */
    public array $config;

    public $saveName;


    /**
     * 本地驱动
     */
    const DRIVER_LOCAL = 'LOCAL';
    /**
     * 阿里云驱动
     */
    const DRIVER_OSS = 'OSS';


    public function __construct()
    {
        $this->config = Laminas::$app->getConfig()['image_uploader'];
        $this->setProperties($this->config);
    }

    /**
     * @param array $arr
     */
    private function setProperties(array $arr)
    {
        foreach ($arr as $k => $v) {
            if (property_exists($this, $k)) {
                $this->{$k} = $v;
            }
        }
    }

    /**
     * 获取适配器
     * @return Local|Oss
     * @throws UploadException
     */
    private function getAdapter()
    {
        switch ($this->driver) {
            case self::DRIVER_LOCAL:
                return new Local($this->config);
            case self::DRIVER_OSS:
                return new Oss($this->config);
            default:
                throw new UploadException("获取适配器失败, 请检查上传驱动配置是否正确。");
        }
    }

    /**
     * 验证上传文件是否符合配置规则
     * @throws UploadException
     */
    private function validate()
    {
        // 文件异常验证
        if ($this->file->getHasError()) {
            throw new InvalidUploadParamException($this->file->getErrorString());
        }

        // 文件大小验证
        if ($this->file->size >= $this->maxSize * 1024 ) {
            throw new InvalidUploadParamException("文件大小不能超过" . $this->maxSize . 'KB');
        }

        // 文件类型验证
        if ($this->allowExtensions && !in_array($this->file->extension, $this->allowExtensions)) {
            throw new InvalidUploadParamException("文件类型{$this->file->extension}不允许被上传");
        }
    }

    /**
     * 将上传的文件转成文件对象
     * @param $file
     * @throws UploadException
     */
    public function setFile($file)
    {
        $this->file = new Image($file);
        // 是否使用自定义文件名称
        if ($this->saveName instanceof \Closure) {
            $this->file->baseName = ($this->saveName)($this->file);
        } elseif (is_string($this->saveName)) {
            $this->file->baseName = call_user_func_array([$this, $this->saveName], [$this->file]);
        }
        $this->validate();
    }

    /**
     * 处理上传图片名称
     * @param Image $image
     * @return string
     */
    protected function handleSaveName(Image $image): string
    {
         // 使用源文件名称
        // return $file->baseName;

        // 使用随机名
        return uniqid(mt_rand(0, 100)) . '_' . time();
    }

    /**
     * @param array $file
     * @return array
     * @throws UploadException
     * @throws FilesystemException
     * @throws OssException
     */
    public function save(array $file): array
    {
        if (!$file) {
            throw new UploadException('未发现上传的文件');
        }
        $this->setFile($file);
        $adapter = $this->getAdapter();
        return $adapter->upload($this->file);
    }


    /**
     * 修改上传配置
     * @param array $config
     * @return ImageUploader
     */
    public function setConfig(array $config): ImageUploader
    {
        $this->setProperties($config);
        return $this;
    }

    /**
     * 获取表单提交过来的文件
     * @param string $name 表单名称
     * @return array|mixed
     */
    public static function getInstanceByName(string $name)
    {
        return $_FILES[$name] ?? [];
    }

    public function DownossFile($uploadFile, $localFile)
    {
        $res = substr($uploadFile,strripos($uploadFile,'=') + 1);

        list($uploadFile,$bucket) = explode('&bucket=',$uploadFile);

        if($bucket){
            $adapter = new Oss($this->config,$bucket);
        }else{
            $adapter = new Oss($this->config);
        }
        $adapter->downOssFile($uploadFile,$localFile);
    }
}