<?php

/**
 * FastIm v1.0.0
 * FastAdmin企业IM客服系统
 * https://www.fastadmin.net/store/fastim.html
 *
 * Copyright 2021 FastAdmin:thinkphp
 *
 * FastAdmin企业IM客服系统不是开源产品，所有文字、图片、样式、风格等版权归企业IM客服系统作者所有，如有复制、仿冒、抄袭、盗用，FastAdmin和企业IM客服系统作者将追究法律责任
 *
 * Released on: November 8, 2021
 */

namespace addons\fastim\controller;

use addons\fastim\library\Common;
use addons\fastim\library\CommonCode;
use app\lib\FileUpload;
use fast\Random;
use think\Config;
use think\Db;
use think\Cookie;
use Exception;
use think\Log;

class Index extends Base
{
    protected $noNeedLogin = [
        'initialize',
        'loadMessagePrompt',
        'upload',
        'mobile',
        'index',
        'icon',
        'getEmoji',
        'getConfigItemData',
        'fullScreen'
    ];

    protected $config;

    protected $userInfo = false;

    protected $tokens = []; // 用于连接ws的token数组

    protected $referrer = ''; // 来源:网址或uni-app

    public function index()
    {
        $this->view->assign('im_name', $this->config['im_name']);
        return $this->view->fetch();
    }

    public function fullScreen()
    {
        $this->view->assign('im_name', $this->config['im_name']);
        return $this->view->fetch();
    }

    public function _initialize()
    {
        parent::_initialize();
        $this->config            = get_addon_config('fastim');
        $this->config['__CDN__'] = config('view_replace_str.__CDN__');
        $imDbConfig              = Db::name('fastim_config')->field('name,value,user_settings')->select();
        foreach ($imDbConfig as $key => $value) {
            if ($value['user_settings'] == 1) {
                $imDefaultUserConfig[$value['name']] = $value['value'];
            } else {
                $imConfig[$value['name']] = $value['value'];
            }
        }

        // 上传配置
        $upload['upload'] = \app\common\model\Config::upload();
        // 上传信息配置后
        \think\Hook::listen("upload_config_init", $upload['upload']);
        if (isset($upload['upload']['storage']) && $upload['upload']['storage'] != 'local') {
            $upload['upload']['uploadurl'] = preg_match('/^http(s)?:\/\//', $upload['upload']['uploadurl']) ? $upload['upload']['uploadurl'] : $this->request->domain() . $upload['upload']['uploadurl'];
        } else {
            $upload['upload']['cdnurl']    = false;
            $upload['upload']['uploadurl'] = addon_url('fastim/index/upload', [], '', true);
        }

        // 来源
        $this->referrer = $this->request->get('referrer') ?? '';

        /**
         * 用户身份识别
         * FastAdmin用户或管理员可转换为ImUser
         * 用户token以前台传递的为主,Cookie内的为辅
         */
        $data                              = $this->request->only(['token', 'im_tourists_token']);
        $this->tokens['token']             = Cookie::get('token');
        $this->tokens['im_tourists_token'] = Cookie::get('im_tourists_token');
        if (!$this->tokens['token'] && isset($data['token'])) {
            $this->tokens['token'] = $data['token'];
        }
        if (isset($data['im_tourists_token'])) {
            $this->tokens['im_tourists_token'] = $data['im_tourists_token'];
        }

        // 若已登录管理员，通过管理员自动登录到im
        $auth = \app\admin\library\Auth::instance();
        if ($auth->isLogin() && $this->referrer != 'uni-app') {
            $this->userInfo = Common::checkAdmin(false, $auth->id);
            if ($this->userInfo) {
                $keeptime   = 864000;
                $expiretime = time() + $keeptime;

                // `$sign`原规则为单纯的id，若需修改附加的字符串，请将`CommonCode::imAuthSign`字符串一起修改
                $sign = $this->userInfo['id'] . CommonCode::$imAuthSign;

                $key                          = md5(md5($sign) . md5($keeptime) . md5($expiretime) . $this->userInfo['token']);
                $tokenData                    = [$this->userInfo['id'], $keeptime, $expiretime, $key];
                $this->tokens['fastim_token'] = implode('|', $tokenData);
                unset($this->userInfo['token']);
            }
        }

        // 若已登录前台用户，通过用户自动登录到fastim
        if (!$this->userInfo && isset($this->tokens['token']) && $this->referrer != 'uni-app') {
            $auth = \app\common\library\Auth::instance();// 多种token来源,重新初始化
            $auth->init($this->tokens['token']);
            if ($auth->isLogin()) {
                $this->userInfo = Common::checkFaUser(null, $auth->id);
                if ($this->userInfo) {
                    if (!config('cookie.httponly')) {
                        $this->tokens['fastim_token'] = $this->tokens['token'];
                    } else {
                        // 需用 user_token 数据表中的token字段同样的加密算法对token进行加密
                        $sign                         = Common::getEncryptedToken($this->tokens['token']);
                        $sign                         .= CommonCode::$imAuthSign;
                        $key                          = md5(md5($auth->id) . md5($sign));
                        $tokenData                    = [$auth->id, $key];
                        $this->tokens['fastim_token'] = implode('|', $tokenData);
                    }
                }
            }
        }
        unset($this->tokens['token']);

        // 用户和管理员以及游客token都可通过此处转换为IMuser
//        $imUser = Common::checkWxIMUser($this->tokens['im_tourists_token'], $this->userInfo);
        $imUser = Common::checkIMUser($this->tokens['im_tourists_token'], $this->userInfo);
        if (!$imUser) {
            if ($this->referrer == 'uni-app') {
                $this->result(null, 402, $imConfig['im_name'] . ' 无法识别用户,请重新登录！', 'json');
            }
            // 建立
//            $imUser = Common::createWxIMUser($this->referrer, $this->request->ip() ?? '',$this->userInfo['']);
            $imUser = Common::createIMUser($this->referrer, $this->request->ip() ?? '');
            if ($imUser) {
                $this->tokens['im_tourists_token'] = $imUser['cache_token'];
                Cookie::set('im_tourists_token', $imUser['cache_token'], 315360000);
            }
        }

        $this->userInfo = Common::bindFaUserToIMUser($imUser, $this->userInfo);
        if (!$this->userInfo) {
            $this->result(null, 401, $imConfig['im_name'] . ' 无法识别用户,请清理浏览器缓存后再试！', 'json');
        }
        unset($imUser);

        // 记录访问日志
        $tourist = ($this->userInfo['identity'] == 'imuser') ? 1 : 0; // imuser必然是游客
        $tourist = ($this->referrer == 'uni-app') ? 0 : $tourist; // 在uni-app端不存在游客与会员区分

        $trajectory = [
            'user_id'    => $this->userInfo['id'],
            'type'       => 0,
            'url'        => $this->request->get('url') ?? '',
            'referrer'   => $this->referrer,
            'ip'         => $this->request->ip(),
            'tourist'    => $tourist,
            'createtime' => time()
        ];
        Db::name('fastim_trajectory')->insert($trajectory);

        // 用户配置
        $imConfigGroup = \app\admin\model\fastim\Config::getConfigListByGroup(1, null);
        $userConfig    = Db::name('fastim_user_config')->where('user_id', $this->userInfo['id'])->column('name,value');
        foreach ($imConfigGroup as $key => $value) {
            foreach ($value['list'] as $k => $v) {
                if (isset($userConfig[$v['name']])) {
                    $imConfigGroup[$key]['list'][$k]['value'] = $userConfig[$v['name']];
                }
            }
        }

        $this->config['user_config'] = array_merge($imDefaultUserConfig, $userConfig);
        $this->config                = array_merge($this->config, $upload, $imConfig);

        if ($this->referrer != 'uni-app') {
            $this->view->assign('imConfigGroup', $imConfigGroup);
            $this->view->assign('userinfo', $this->userInfo);
        }
    }

    public function initialize()
    {
        // 清理轨迹
        switch ($this->config['trajectory_save_cycle']) {
            case 0:
                $clearWhereTime = 604800; // 清理7天前的
                break;
            case 1:
                $clearWhereTime = 2592000; // 30天
                break;
            case 2:
                $clearWhereTime = 5184000; // 60天
                break;

            default:
                $clearWhereTime = false; // 不清理
                break;
        }
        if ($clearWhereTime) {
            Db::name('fastim_trajectory')->where('createtime', '<', time() - $clearWhereTime)->delete();
        }

        // 配置排除
        $except_config = [
            '__tips__',
            'reactor_num',
            'worker_num',
            'ssl_cert_file',
            'ssl_key_file',
            'configgroup',
            'trajectory_save_cycle'
        ];
        foreach ($except_config as $key => $value) {
            if (array_key_exists($value, $this->config)) {
                unset($this->config[$value]);
            }
        }

        // 表情包数据
        $emoji = Db::name('fastim_emoji')->where('status', '1')->order('weigh desc')->select();
        foreach ($emoji as $key => $value) {
            $emoji[$key]['image'] = cdnurl($value['image'], true);
        }

        // 快捷回复
        if ($this->userInfo['type'] == 'csr') {
            $fastReply = Db::name('fastim_fast_reply')->field('id,title,content')->where(function ($query) {
                $query->where('user_id', $this->userInfo['id'])->whereOr('user_id', 0);
            })->where('status', '1')->where('deletetime', null)->order('user_id desc,createtime desc')->select();
            if ($this->referrer != 'uni-app') {
                $this->view->assign('fast_reply', $fastReply);
            } else {
                $this->config = array_merge($this->config, ['fast_reply' => $fastReply]);
            }
        }

        if ($this->referrer != 'uni-app') {
            $this->view->assign('emoji', $emoji);
            $this->view->assign('user_type', $this->userInfo['type']);
            $res['window'] = $this->view->fetch(ROOT_PATH . 'addons/fastim/view/' . trim($this->config['theme']) . '/pc.html', [], ['__CDN__' => $this->config['__CDN__'] ? $this->config['__CDN__'] : cdnurl('', true)]);

            // 最后未读消息
            $res['unreadMessage'] = Common::getUnreadMessage($this->userInfo['id'], false);
        }
        $res['tokens']   = $this->tokens;
        $res['userinfo'] = $this->userInfo;
        $res['config']   = $this->config;
        $this->result($res, 1, 'ok', 'json');
    }

    /**
     * 供跨站下载来信提示音文件（未使用云存储）
     */
    public function loadMessagePrompt()
    {
        $file = ROOT_PATH . 'public' . $this->config['ringing'];
        header("Content-type:application/octet-stream");
        $filename = basename($file);
        header("Content-Disposition:attachment;filename = " . $filename);
        header("Accept-ranges:bytes");
        header("Accept-length:" . filesize($file));
        readfile($file);
    }

    /**
     * 上传文件
     */
   /* public function upload()
    {
        $file = $this->request->file('file');
        if (empty($file)) {
            $this->result(null, 0, $this->config['im_name'] . '没有文件被上传~', 'json');
        }
        try {
            $upload     = new \app\common\library\Upload($file);
            $attachment = $upload->upload();
        } catch (app\common\exception\UploadException $e) {
            $this->result(null, 0, $e->getError(), 'json');
        } catch (Exception $e) {
            $this->result(null, 0, $e->getMessage(), 'json');
        }

        $this->result([
            'url'     => $attachment->url,
            'fullurl' => cdnurl($attachment->url, true)
        ], 1, __('Uploaded successful'), 'json');
    }*/
    public function upload()
    {
        Config::set('default_return_type', 'json');
        $file = $this->request->file('file');
//        $water = $this->request->post('water',0);;//是否水印 0否，1是
        if (empty($file)) {
            $this->result(null, 0, __('No file upload or server upload limit exceeded'), 'json');
//            $this->error(__('No file upload or server upload limit exceeded'));
        }
        //判断是否已经存在附件
        $sha1 = $file->hash();
        $extparam = $this->request->post();
        unset($extparam['name']);
        $upload = Config::get('upload');
        $multipart=$upload['multiparameter'];
        $url='';
        if($extparam){
            foreach ($extparam as $key=>$val){
                if(is_numeric($key)){
                    $multipart =$multipart.$val;
                    $url = $url.$val;
                }
            }
//            $multipart =$multipart."/";
            $url=$upload['cdnurl'].$url;
        }
        preg_match('/(\d+)(\w+)/', $upload['maxsize'], $matches);
        $type = strtolower($matches[2]);

        $typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3];
        $size = (int)$upload['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0);
        $fileInfo = $file->getInfo();
        $suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
        $suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file';

        $mimetypeArr = explode(',', strtolower($upload['mimetype']));
        $typeArr = explode('/', $fileInfo['type']);

        //禁止上传PHP和HTML文件
        if (in_array($fileInfo['type'], ['text/x-php', 'text/html']) || in_array($suffix, ['php', 'html', 'htm'])) {
            $this->result(null, 0, __('Uploaded file format is limited'), 'json');
//            $this->error(__('Uploaded file format is limited'));
        }
        //验证文件后缀
        if ($upload['mimetype'] !== '*' &&(!in_array($suffix, $mimetypeArr)
                || (stripos($typeArr[0] . '/', $upload['mimetype']) !== false && (!in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr))))) {
            $this->result(null, 0, __('Uploaded file format is limited'), 'json');
//            $this->error(__('Uploaded file format is limited'));
        }
        //判断图片是否过大
        if($fileInfo['size']>$size){
            $this->result(null, 0, __('上传文件过大！'), 'json');
//            $this->error("上传文件过大！");
        }
        //验证是否为图片文件或视频文件
        $imagewidth = $imageheight = 0;
        if (in_array($fileInfo['type'], ['image/gif', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/png', 'image/webp']) || in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'webp', 'swf', 'mp4', 'mp3', 'avi', 'flv', 'wmv', 'wav'])) {
            $imgInfo = getimagesize($fileInfo['tmp_name']);
           /* if (!$imgInfo || !isset($imgInfo[0]) || !isset($imgInfo[1])) {
                $this->result(null, 0, __('Uploaded file is not a valid image'), 'json');
//                $this->error(__('Uploaded file is not a valid image'));
            }*/
            $imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth;
            $imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight;
        }
        $replaceArr = [
            '{year}' => date("Y"),
            '{mon}' => date("m"),
            '{day}' => date("d"),
            '{hour}' => date("H"),
            '{min}' => date("i"),
            '{sec}' => date("s"),
            '{random}' => Random::alnum(16),
            '{random32}' => Random::alnum(32),
            '{filename}' => $suffix ? substr($fileInfo['name'], 0, strripos($fileInfo['name'], '.')) : $fileInfo['name'],
            '{suffix}' => $suffix,
            '{.suffix}' => $suffix ? '.' . $suffix : '',
            '{filemd5}' => substr(md5($fileInfo['tmp_name'].time()),-18),
        ];
        $savekey = $upload['savekey'];
        $savekey = str_replace(array_keys($replaceArr), array_values($replaceArr), $savekey);
        $uploadDir = substr($savekey, 0, strripos($savekey, '/') + 1);
        $fileName = substr($savekey, strripos($savekey, '/') + 1);
        $res = FileUpload::image($multipart.$uploadDir.$fileName, $fileInfo['tmp_name']);
        Log::record("上传是否成功".$res, 'debug');//记录错误
        if($res){
            $this->result([
                'url' =>$multipart.$uploadDir.$fileName,
                'cdnurl'=>$upload['cdnurl'],
            ], 1, __('Uploaded successful'), 'json');
            /*$this->success('上传成功',[
                'url' =>$multipart.$uploadDir.$fileName,
                'cdnurl'=>$upload['cdnurl'],
            ]);*/
        }else{
            // 上传失败获取错误信息
            $this->result(null, 0, $file->getMessage(), 'json');
//            $this->error($file->getError());
        }
    }

    /**
     * uni-app获取emoji
     */
    public function getEmoji()
    {
        // 表情包数据
        $emoji = Db::name('fastim_emoji')->where('status', '1')->order('weigh desc')->select();
        foreach ($emoji as $key => $value) {
            $emoji[$key]['image'] = cdnurl($value['image'], true);
        }

        $this->result([
            'emoji' => $emoji
        ], 1, 'ok', 'json');
    }

    /**
     * uni-app获得用户设置项
     */
    public function getConfigItemData()
    {
        $imConfigGroup = \app\admin\model\fastim\Config::getConfigListByGroup(1, null, 1);
        $userConfig    = Db::name('fastim_user_config')->where('user_id', $this->userInfo['id'])->column('name,value');
        foreach ($imConfigGroup as $key => $value) {
            foreach ($value['list'] as $k => $v) {
                if (isset($userConfig[$v['name']])) {
                    if (in_array($imConfigGroup[$key]['list'][$k]['type'], ['select', 'selects', 'checkbox'])) {
                        $userConfig[$v['name']] = explode(',', $userConfig[$v['name']]);
                    }
                    $imConfigGroup[$key]['list'][$k]['value'] = $userConfig[$v['name']];
                }
            }
        }

        $this->result([
            'imConfigGroup' => $imConfigGroup
        ], 1, 'ok', 'json');
    }

    /**
     * 生成文件类型 icon
     */
    public function icon()
    {
        $suffix = $this->request->param("suffix");
        header('Content-type: image/svg+xml');
        $suffix = $suffix ? $suffix : "FILE";
        echo Common::buildSuffixImage($suffix);
        exit;
    }
}
