<?php

/**
 * 文件地址
 * @author solu
 */

use Aws\S3\S3Client;

class FileUrl extends Model {
    protected $tableName = 'file_url';
    protected $dbKey = 'dw_chat';

    const TMP_DIR = '/tmp/mee';

    const TYPE_OTHER = 0; // 其他
    const TYPE_IMAGE = 1; // 图片
    const TYPE_VIDEO = 2; // 视频
    const TYPE_AUDIO = 3; // 音频

    private static $arrType = [
        self::TYPE_OTHER => '其他',
        self::TYPE_IMAGE => '图片',
        self::TYPE_VIDEO => '视频',
        self::TYPE_AUDIO => '音频',
    ];

    public static function getAllType() {
        return self::$arrType;
    }

    /**
     * @param $tmpPath
     * @param $filename
     * @param $mimeType
     * @param $forever
     * @return mixed|null
     * @throws Exception
     */
    public function getFileUrl($tmpPath, $filename, $mimeType, $forever = false) {
        // 控制频率
        $objLock = new Lock('file_upload', 300, 50);
        $uid = User::getUserId();
        $objLock->lock($uid);

        if (!file_exists($tmpPath)) {
            throw new Exception('file not exists', CODE_PARAM_ERROR);
        }

        $md5 = md5_file($tmpPath);
        $row = $this->objTable->getRow(['id' => $md5]);
        if ($row['forever'] || (strtotime($row['update_time'])+20*86400 > time())) {
            return $row['url'];
        }

        $ext = pathinfo($filename, PATHINFO_EXTENSION);
        $type = self::getType($mimeType);
        $filename = self::getFileName($md5, $tmpPath, $type, $ext);

        $url = self::s3PutObject($tmpPath, $filename, $mimeType, $forever);
        if ($url) {
            $this->objTable->replaceObject([
                'id' => $md5,
                'url' => $url,
                'type' => $type,
                'update_time' => date('Y-m-d H:i:s'),
                'forever' => $forever ? 1 : 0,
            ]);
        }

        $objLock->unlock($uid);
        return $url;
    }

    private static function getFileName($md5, $path, $type, $ext = '') {
        $len = filesize($path);
        if ($type == self::TYPE_IMAGE) {
            $arr = getimagesize($path);
            $str = sprintf('%s_%s_%s', $md5, "size{$arr[0]}x{$arr[1]}", "len{$len}");
        } else {
            $str = sprintf('%s_%s', $md5, "len{$len}");
        }
        $ext && $str .= ".{$ext}";

        return $str;
    }

    /**
     * 获取类型
     * @author solu
     * @param $mineType
     * @return int
     */
    public static function getType($mineType) {
        if (false !== strpos($mineType, 'image')) {
            return self::TYPE_IMAGE;
        } elseif (false !== strpos($mineType, 'video')) {
            return self::TYPE_VIDEO;
        } elseif (false !== strpos($mineType, 'audio')) {
            return self::TYPE_AUDIO;
        }

        return self::TYPE_OTHER;
    }

    /**
     * 上传文件
     * @author solu
     * @param $path
     * @param $name
     * @param $mime
     * @param $forever
     * @return string
     * @throws Exception
     */
    private static function s3PutObject($path, $name, $mime, $forever = false) {
        $s3 = new S3Client([
            'version' => 'latest',
            'region' => 'ap-northeast-1',
            'scheme'  => 'http',
            'credentials' => [
                'key' => AWS_ACCESS_KEY,
                'secret' => AWS_SECRET_KEY,
            ],
        ]);

        $bucket = $forever ? BUCKET_MEE : BUCKET_MEE_TMP;
        $option = [
            'Bucket' => $bucket,
            'Key' => $name,
            'CacheControl' => 'max-age=8640000', // 前端缓存100天
            'Body' => fopen($path, 'r'),
            'ACL' => 'public-read',
            'ContentType' => $mime,
        ];
        $result = $s3->putObject($option);

        $url = $result->get('ObjectURL');
        if (!$url) {
            throw new Exception('upload to s3 error', CODE_NORMAL_ERROR);
        }

        return self::_fixUrl($url, $forever);
    }

    /**
     * 转换url
     * @author solu
     * @param $url
     * @param $forever
     * @return string
     */
    private static function _fixUrl($url, $forever = false) {
        $cdn = $forever ? CDN_HOST : CDN_HOST_TMP;
        if (strpos($url, $cdn) === false) {

            $pos = strrpos($url, '/') + 1;
            $path = substr($url, $pos);

            return sprintf('https://%s/%s', $cdn, $path);
        }

        return $url;
    }

}