<?php


namespace App\Services;


use App\Utils\Image;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Storage;

class FileService
{

    public static function SetAttachUrl($uniacid=null) {
        global $_W;
        $uniacid = $uniacid===null ? $_W['uniacid'] : intval($uniacid);
        if(empty($_W['setting']['remote_complete_info'])){
            $_W['setting']['remote_complete_info'] = $_W['setting']['remote'];
        }
        $storage = serv('storage', intval($uniacid));
        if ($storage->enabled){
            $_W['setting']['remote'] = $storage->settings['remote'];
            if ($storage->uniacid==0){
                $_W['setting']['remote_complete_info'] = $_W['setting']['remote'];
            }
        }
        $attach_url = $_W['attachurl_local'] = $_W['siteroot'] . $_W['config']['upload']['attachdir'] . '/';
        if (!empty($_W['setting']['remote']['type'])) {
            $attach_url = self::getRemoteUrl($_W['setting']['remote']);
            $_W['attachurl_remote'] = $attach_url;
        }
        $_W['attachurl_global_remote'] = '';
        if ($uniacid===0){
            $_W['attachurl_global'] = $attach_url;
            if (!empty($_W['setting']['remote']['type'])){
                $_W['attachurl_global_remote'] = $attach_url;
            }
        }
        return $attach_url;
    }

    public static function getRemoteUrl($remoteSet){
        switch ($remoteSet['type']) {
            case 1:
                $attach_url = $remoteSet['ftp']['url'] . '/';
                break;
            case 2:
                $attach_url = $remoteSet['alioss']['url'] . '/';
                break;
            case 3:
                $attach_url = $remoteSet['qiniu']['url'] . '/';
                break;
            case 4:
                $attach_url = $remoteSet['cos']['url'] . '/';
                break;
            default:
                //aws
                Config::set('filesystems.default', 's3');
                $attach_url = config('filesystems.disks.s3.url') . '/';
        }
        return $attach_url;
    }

    public static function file_write($filename, $data) {
        $uri = ATTACHMENT_ROOT . '/' . $filename;
        $path = dirname($uri);
        self::mkdirs($path);
        Storage::put($filename, $data);
        return is_file($uri);
    }

    public static function file_download($url, $savePath='', $timeout=60){
        global $_W;
        if (\Str::startsWith($url, "//")){
            $url = $_W['sitescheme'] . substr($url, 2);
        }
        if(function_exists('curl_init')) {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_VERBOSE, 1);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_AUTOREFERER, false);
            curl_setopt($ch, CURLOPT_REFERER, $_W['siteurl']);
            curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
            $fileContent = curl_exec($ch);
            curl_close($ch);
            if (empty($fileContent) ){
                return false;
            }
        } else {
            $opts = array(
                "http"=>array(
                    "method"=>"GET",
                    "header"=>"",
                    "timeout"=>$timeout)
            );
            $context = stream_context_create($opts);
            $fileContent = file_get_contents($url, false, $context);
            if (empty($fileContent)) return false;
        }
        if (!empty($savePath)){
            return file_put_contents($savePath, $fileContent);
        }
        return $fileContent;
    }

    public static function file_move($filename, $dest) {
        global $_W;
        self::mkdirs(dirname($dest));
        if (is_uploaded_file($filename)) {
            move_uploaded_file($filename, $dest);
        } else {
            rename($filename, $dest);
        }
        @chmod($filename, $_W['config']['setting']['filemode']);

        return is_file($dest);
    }

    static function file_tree($path, $include = null) {
        $files = array();
        $path = realpath($path);
        if (!empty($include)) {
            if(is_array($include) && count($include)>1){
                $ds = glob($path . '/{' . implode(',', $include) . '}', GLOB_BRACE);
            }else{
                $pattern = is_array($include) ? $include[0] : $include;
                $ds = glob($path . "/" . $pattern);
            }
        } else {
            $ds = glob($path . '/*');
        }
        if (is_array($ds)) {
            foreach ($ds as $entry) {
                if (is_file($entry)) {
                    $files[] = $entry;
                }
                if (is_dir($entry)) {
                    $rs = self::file_tree($entry);
                    foreach ($rs as $f) {
                        $files[] = $f;
                    }
                }
            }
        }

        return $files;
    }

    public static function mkdirs($path, $perm=0777, $rec=false) {
        if (!is_dir($path)) {
            self::mkdirs(dirname($path));
            mkdir($path, $perm, $rec);
        }

        return is_dir($path);
    }

    public static function rmdirs($path, $clean = false) {
        if (!is_dir($path)) {
            return true;
        }
        $files = glob($path . '/*');
        if ($files) {
            foreach ($files as $file) {
                is_dir($file) ? self::rmdirs($file) : @unlink($file);
            }
        }

        return $clean || @rmdir($path);
    }

    static function Upload(Request $request,$type='image',$field='file'){
        global $_W;
        if (!$request->hasFile($field)) return error(-1,__('uploadValid'));
        if (!in_array($type, array('image', 'media', 'attach'))) {
            return error(-2, __('uploadValid'));
        }
        $harmtype = array('asp', 'php', 'jsp', 'js', 'css', 'php3', 'php4', 'php5', 'ashx', 'aspx', 'exe', 'cgi');
        $Upload = $request->file($field);
        $ext = $Upload->getClientOriginalExtension();
        $size = $Upload->getSize();
        $setting = SettingService::Load('upload');
        if (in_array($ext, $harmtype)){
            return error(-3, __('attachExtInvalid',['ext'=>$ext]));
        }
        if ($type!='attach'){
            $allowExt = $setting['upload'][$type]['extentions'];
            $limit = $setting['upload'][$type]['limit'];
            if (!in_array($ext, $allowExt)) {
                return error(-3, __('attachExtInvalid',['ext'=>$ext]));
            }
            if (!empty($limit) && $limit * 1024 < $size) {
                return error(-4, __('attachSizeInvalid', ['size'=>$size]));
            }
        }
        $path = $Upload->store("{$type}s/{$_W['uniacid']}/".date('Y/m'));
        if (!$path) return error(-1,__('uploadFailed'));
        //图片压缩
        if ($type=='image'){
            $quality = intval($setting['upload']['image']['zip_percentage']);
            if ($quality>0 && $quality<100){
                $savepath = ATTACHMENT_ROOT . $path;
                self::file_image_quality($savepath, $savepath, $ext);
            }
        }
        return array(
            "path"=>$path,
            "success"=>true
        );
    }

    static function file_upload($file, $type = 'image', $name = '', $compress = false) {
        $harmtype = array('asp', 'php', 'jsp', 'js', 'css', 'php3', 'php4', 'php5', 'ashx', 'aspx', 'exe', 'cgi');
        if (empty($file)) {
            return error(-1, __('uploadValid'));
        }
        if (!in_array($type, array('image', 'thumb', 'voice', 'video', 'audio'))) {
            return error(-2, __('uploadValid'));
        }
        global $_W;
        $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
        $ext = strtolower($ext);
        $setting = SettingService::Load('upload');
        switch ($type) {
            case 'image':
            case 'thumb':
                $allowExt = array('gif', 'jpg', 'jpeg', 'bmp', 'png', 'ico');
                $limit = $setting['upload']['image']['limit'];
                break;
            case 'voice':
            case 'audio':
                $allowExt = array('mp3', 'wma', 'wav', 'amr');
                $limit = $setting['upload']['audio']['limit'];
                break;
            case 'video':
                $allowExt = array('rm', 'rmvb', 'wmv', 'avi', 'mpg', 'mpeg', 'mp4');
                $limit = $setting['upload']['audio']['limit'];
                break;
        }
        $type_setting = in_array($type, array('image', 'thumb')) ? 'image' : 'audio';
        $setting = $_W['setting']['upload'][$type_setting];

        if (!empty($setting['extentions'])) {
            $allowExt = $setting['extentions'];
        }
        if (!in_array(strtolower($ext), $allowExt) || in_array(strtolower($ext), $harmtype)) {
            return error(-3, __('attachExtInvalid',['ext'=>$ext]));
        }
        $size = filesize($file['tmp_name']);
        if (!empty($limit) && $limit * 1024 < $size) {
            return error(-4, __('attachSizeInvalid', ['size'=>$size]));
        }

        $result = array();
        if (empty($name) || 'auto' == $name) {
            $uniacid = intval($_W['uniacid']);
            $path = "{$type}s/{$uniacid}/" . date('Y/m/');
            self::mkdirs(ATTACHMENT_ROOT . '/' . $path);
            $filename = self::file_random_name(ATTACHMENT_ROOT . '/' . $path, $ext);

            $result['path'] = $path . $filename;
        } else {
            self::mkdirs(dirname(ATTACHMENT_ROOT . '/' . $name));
            if (!strexists($name, $ext)) {
                $name .= '.' . $ext;
            }
            $result['path'] = $name;
        }

        $save_path = ATTACHMENT_ROOT . '/' . $result['path'];

        $image = '';
        if (isset($setting['zip_percentage']) && $setting['zip_percentage'] == 100 && SettingService::check_php_ext('exif')) {
            $exif = exif_read_data($file['tmp_name']);
            if (!empty($exif['THUMBNAIL']['Orientation'])) {
                $image = imagecreatefromstring(file_get_contents($file['tmp_name']));
                switch($exif['THUMBNAIL']['Orientation']) {
                    case 3:
                        $image = imagerotate($image,180,0);
                        break;
                    case 6:
                        $image = imagerotate($image,-90,0);
                        break;
                    case 8:
                    default:
                        $image = imagerotate($image,0,0);
                        break;
                }
            }
        }
        if (empty($image)) {
            $newimage = self::file_move($file['tmp_name'], $save_path);
        } else {
            $newimage = imagejpeg($image,$save_path);
            imagedestroy($image);
        }
        if (empty($newimage)) {
            return error(-1, __('uploadFailed'));
        }

        if ('image' == $type && $compress) {
            self::file_image_quality($save_path, $save_path, $ext);
        }

        if (self::file_is_uni_attach($save_path)) {
            $check_result = self::file_check_uni_space($save_path);
            if (is_error($check_result)) {
                @unlink($save_path);

                return $check_result;
            }

            $storage = serv('storage');
            if (empty($storage->settings['remote']['type'])) {
                self::file_change_uni_attchsize($save_path);
            }
        }

        $result['success'] = true;

        return $result;
    }

    public static function file_remote_upload($filename, $auto_delete_local = true) {
        $result = serv('storage')->remoteUpload($filename);
        if (is_error($result)) return $result;
        if ($auto_delete_local) {
            self::file_delete($filename);
        }
        return true;
    }

    public static function file_random_name($dir, $ext) {
        do {
            $filename = random(30) . '.' . $ext;
        } while (file_exists($dir . $filename));

        return $filename;
    }

    public static function file_delete($file) {
        global $_W;
        if (empty($file)) {
            return false;
        }
        $file_extension = pathinfo($file, PATHINFO_EXTENSION);
        if (in_array($file_extension, array('php', 'html', 'js', 'css', 'ttf', 'otf', 'eot', 'svg', 'woff'))) {
            return false;
        }

        $storage = serv('storage');
        if (empty($storage->settings['remote']['type'])) {
            if (file_exists(ATTACHMENT_ROOT . '/' . $file) && self::file_is_uni_attach(ATTACHMENT_ROOT . '/' . $file)) {
                self::file_change_uni_attchsize(ATTACHMENT_ROOT . '/' . $file, false);
            }
        }
        if (file_exists($file)) {
            @unlink($file);
        }
        if (file_exists(ATTACHMENT_ROOT . '/' . $file)) {
            @unlink(ATTACHMENT_ROOT . '/' . $file);
        }

        return true;
    }

    public static function file_image_quality($src, $to_path, $ext) {
        global $_W;
        if ('gif' == strtolower($ext)) {
            return false;
        }
        $quality = intval($_W['setting']['upload']['image']['zip_percentage']);
        if ($quality <= 0 || $quality >= 100) {
            return false;
        }

        if (filesize($src) / 1024 > 5120) {
            return false;
        }

        $result = Image::create($src, $ext)->saveTo($to_path, $quality);

        return $result;
    }

    public static function file_is_uni_attach($file) {
        global $_W;
        if (!is_file($file) || !$_W['uniacid']) {
            return false;
        }

        return strpos($file, "/{$_W['uniacid']}/") > 0;
    }

    public static function file_check_uni_space($file) {
        if (!is_file($file)) {
            return error(-1, __('uploadValid'));
        }
        $uni_remote_setting = SettingService::uni_load('remote');
        if (empty($uni_remote_setting['remote']['type'])) {
            $uni_setting = SettingService::uni_load(array('attachment_limit', 'attachment_size'));

            $attachment_limit = intval($uni_setting['attachment_limit']);
            if (0 == $attachment_limit) {
                $upload = SettingService::Load('upload');
                $attachment_limit = empty($upload['upload']['attachment_limit']) ? 0 : intval($upload['upload']['attachment_limit']);
            }

            if ($attachment_limit > 0) {
                $file_size = max(1, round(filesize($file) / 1024));
                if (($file_size + $uni_setting['attachment_size']) > ($attachment_limit * 1024)) {
                    return error(-1, __('uploadFailedLimit'));
                }
            }
        }

        return true;
    }

    public static function file_change_uni_attchsize($file, $is_add = true) {
        global $_W;
        if (!is_file($file)) {
            return error(-1, __('uploadValid'));
        }
        $file_size = round(filesize($file) / 1024);
        $file_size = max(1, $file_size);

        $result = true;
        $storage = serv('storage');
        if (empty($storage->settings['remote']['type']) && !empty($_W['uniacid'])) {
            $uni_settings = pdo_get('uni_settings', array('uniacid' => $_W['uniacid']), array('uniacid','attachment_size'));
            if (empty($uni_settings)) {
                $result = pdo_insert('uni_settings', array('attachment_size' => $file_size, 'uniacid' => $_W['uniacid']));
            } else {
                if (!$is_add) {
                    $file_size = -$file_size;
                }
                $result = pdo_update('uni_settings', array('attachment_size' => (intval($uni_settings['attachment_size']) +$file_size)), array('uniacid' => $_W['uniacid']));
            }
            $uniacid = $_W['uniacid'];

            $cachekey = CacheService::system_key('unisetting', array('uniacid' => $uniacid));
            $unisetting = Cache::get($cachekey);
            $unisetting['attachment_size'] += $file_size;
            $unisetting['attachment_size'] = max(0, $unisetting['attachment_size']);
            Cache::put($cachekey, $unisetting,86400*7);
        }

        return $result;
    }

}
