<?php
/**
 * +------------------------------------------------------------
 * | 公众号 wechat/controller/Index.php
 * +------------------------------------------------------------
 * | @author: bsh (844783437@qq.com)
 * | @create_time: 2018/5/28
 * +------------------------------------------------------------
 * | @copyright: CIM (https://cimxx.com)
 * +------------------------------------------------------------
 * | @last_modified_by: bsh
 * | @last_modified_time: 2018/5/28
 * +------------------------------------------------------------
 * | @todo:
 * +------------------------------------------------------------
 */

namespace app\wechat\controller;

use EasyWeChat\Factory;
use EasyWeChat\Kernel\Messages\Image;
use EasyWeChat\Kernel\Messages\Voice;
use EasyWeChat\Kernel\Messages\Media;
use EasyWeChat\Kernel\Messages\News;
use EasyWeChat\Kernel\Messages\NewsItem;
use think\Env;

class Index extends Module
{
    protected $app;

    function initialize()
    {
        parent::initialize();
        $this->app = Factory::OfficialAccount($this->config['OfficialAccount']);
        if (!in_array(self::$sys['action'], ['oauth'])) {
            if (empty($this->config['OfficialAccount']['app_id']) || empty($this->config['OfficialAccount']['secret'])) die(json_encode(['code' => 41001, 'msg' => '请配置公众号参数']));
        }
    }

    /**
     * js签名
     */
    public function sign($url = '')
    {
        try {
            $js = $this->app->jssdk;
            if ($url) $js->setUrl($url);
            $data = $js->buildConfig(array(), $debug = false, $beta = false, $json = false);
            return json(['code' => 1, 'data' => $data]);
        } catch (\Exception $e) {
            return json(['code' => 41002, 'msg' => $e->getMessage()]);
        }
    }

    /**
     * 授权
     */
    public function oauth()
    {
        $key = create_str();
        $url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' . config('')['wechat']['OfficialAccount']['app_id'] . '&redirect_uri=' . urlencode($this->request->domain() . '/wechat/index/oauth_callback') . '&response_type=code&scope=snsapi_userinfo&state=' . $key . '#wechat_redirect';
        if (!empty(input('param.url'))) {
            cache($key, ['url' => input('param.url')]);
        }
        Header("Location: $url");
        exit;
    }

    /**
     * 授权回调
     */
    public function oauth_callback()
    {
        $param = input('param.');
        try {
            $oauth = $this->app->oauth;
            $user = $oauth->user()->toArray();
            if (!empty(cache($param['state'])['url'])) {
                $openid = $user['id'];
                $result = action('user/api/register', [2, ['openid' => $openid, 'type' => 1, 'name' => $user['name']], 0]);
                if ($result['code'] == 0) {
                    $result = action('user/api/login', [2, ['openid' => $openid, 'oauth_type' => 1], 0]);
                } else {
                    $user_id = $result['data']['id'];
                    $avatar = file_get_contents($user['avatar']);
                    file_put_contents(\Env::get('root_path') . 'public' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'avatar' . DIRECTORY_SEPARATOR . ceil($user_id / 10000) . DIRECTORY_SEPARATOR . $user_id . '.png', $avatar);
                }
                $var = (strpos(urldecode(cache($param['state'])['url']), '\?') !== false) ? '&' : '?';
                if (!empty($result['data']['token'])) {
                    $url = urldecode(cache($param['state'])['url']) . $var . 'token=' . $result['data']['token'];
                } else {
                    $url = urldecode(cache($param['state'])['url']) . $var . 'token=';
                }
                cache($param['state'], null);
                Header("Location: $url");
                exit;
            }
        } catch (\Exception $e) {

        }
    }

    /**
     * 二维码
     */
    public function qrcode()
    {
        $qrcode = $this->app->qrcode;
        $result = $qrcode->temporary(rand(10000, 99999), 60);
        $ticket = $result['ticket'];
        $result['url'] = $this->qrcode_url(urlencode($ticket));
        cache($ticket, ['time' => time() + 60], 60);
        return json(['code' => 1, 'msg' => '加载成功', 'data' => $result]);
    }

    /*
     * 获取二维码网址
     */
    public function qrcode_url($ticket = '')
    {
        if (!$ticket) return;
        $qrcode = $this->app->qrcode;
        return $qrcode->url($ticket);
    }

    /**
     * 获取二维码内容
     * @param string $ticket
     * @return bool|string|void
     */
    public function qrcode_content($ticket = '')
    {
        if (!$ticket) return;
        $qrcode = $this->app->qrcode;
        $url = $qrcode->url($ticket);
        $content = file_get_contents($url);
        return $content;
    }

    /**
     * 消息处理
     */
    public function message()
    {
        $server = $this->app->server;
        $server->push(function ($message) {
            $openid = $message['FromUserName'];
            switch ($message['MsgType']) {
                case 'event':
                    if (!empty($message['Ticket'])) {
                        $ticket = $message['Ticket'];
                        $cache = cache($ticket);
                        if (empty($cache) || $cache['time'] < time()) {
                            $cache['code'] = -1;
                            $msg = '二维码已过期';
                        } else {
                            $result = action('user/api/register', [2, ['type' => 1, 'openid' => $openid], 'json' => 0]);
                            if ($result['code'] == 1) {
                                $msg = '登录成功';
                                $cache['data'] = session('user');
                                $cache['code'] = 1;
                            } else {
                                $result = action('user/api/login', [2, ['oauth_type' => 1, 'openid' => $openid], 'json' => 0]);
                                if ($result['code'] == 1) {
                                    $cache['data'] = session('user');
                                    $cache['code'] = 1;
                                    $msg = '登录成功';
                                } else {
                                    $cache['code'] = 0;
                                    $msg = $result['msg'];
                                }
                            }
                        }
                        cache($ticket, $cache, 60);
                        return $msg;
                    }
                    if ($message['Event'] == 'subscribe') {
                        $msg = db('wechat_reply')->where('key', '=', 'subscribe')->find();
                    }
                    break;
                case 'text':
                    $content = db('wechat_reply')->where('status', '=', 1)->where('key', 'in', ['default', $message['Content']])->column('*', 'key');
                    $msg = isset($content[$message['Content']]) ? $content[$message['Content']] : (isset($content['default']) ? $content['default'] : '');
                    break;
                default :
                    $msg = db('wechat_reply')->where('key', '=', 'default')->where('status', '=', 1)->find();
                    break;
            }
            if (empty($msg)) return '';
            if ($msg['type'] == 'text') return $msg['content'];
            if ($msg['type'] == 'image') return new Image($msg['content']);
            if ($msg['type'] == 'news') return new News($this->media($msg['content']));
            if ($msg['type'] == 'voice') return new Voice($msg['content']);
        });
        $response = $server->serve();
        $response->send();
    }

    /**
     * 处理回复文章或图文素材
     */
    public function media($media_id = '')
    {
        if ($media_id) {
            $resource = $this->app->material->get($media_id);
            if (!empty($resource['news_item'])) {
                $item = [];
                foreach ($resource['news_item'] as $k => $v) {
                    $item[] = new NewsItem([
                        'title' => $v['title'],
                        'description' => $v['digest'],
                        'url' => $v['url'],
                        'image' => $v['thumb_url']
                    ]);
                }
                return $item;
            }
        }
        return '';
    }

    /**
     * 菜单设置
     */
    public function menu($button = [])
    {
        if (request()->isPost()) {
            try {
                $result = $this->app->menu->create($button);
                if ($result['errcode'] == 0) {
                    return json(['code' => 1, 'msg' => '菜单设置成功']);
                } else {
                    return json(['code' => $result['errcode'], 'msg' => $result['errmsg']]);
                }
            } catch (\ErrorException $e) {
                return json(['code' => 41003, 'msg' => $e->getCode()]);
            }
        } else {
            try {
                $data = $this->app->menu->list();
                return json(['code' => 1, 'data' => $data]);
            } catch (\Exception $e) {
                return json($this->err($e->getMessage()));
            }
        }
    }

    /**
     * 回复管理
     */
    public function reply($id = 0, $key = '', $status = '', $delete = '')
    {
        if (request()->isPost()) {
            $data = [
                'id' => input('post.id', 0),
                'key' => input('post.key', ''),
                'type' => input('post.type', ''),
                'content' => input('post.content', ''),
                'status' => input('post.status', 1),
                'ext' => input('post.ext', '')
            ];
            $validate = validate('app\wechat\validate\Reply');
            if ($validate->check($data) !== true) return json(['code' => 41004, 'msg' => $validate->getError()]);
            if (!in_array($data['key'], ['subscribe', 'default']) && !$id) {
                $reply = db('wechat_reply')->where('key', '=', $data['key'])->find();
                if (!empty($reply) && $reply['key'] == $data['key']) {
                    if (($id && $reply['id'] != $id) || $id) return json(['code' => 41005, 'msg' => '关键字已存在']);
                }
            }
            if (in_array($data['type'], ['image', 'voice'])) {
                $cache = cache($data['content']);
                if (!empty($cache)) {
                    rename($cache['path'], rtrim($cache['path'], $cache['name']) . $data['content'] . '.' . $cache['ext']);
                    $data['ext'] = $cache['ext'];
                    cache($data['content'], null);
                }
            }
            if ($id) {
                db('wechat_reply')->where('id', '=', $id)->update($data);
            } else {
                db('wechat_reply')->insert($data);
            }
            return json(['code' => 1, 'msg' => '操作成功']);
        } else {
            if ($id) {
                if ($status !== '') {
                    db('wechat_reply')->where('id', 'in', (array)$id)->setField('status', intval($status));
                    return json(['code' => 1, 'msg' => '操作成功']);
                }
                if ($delete !== '') {
                    $data = db('wechat_reply')->where('id', 'in', (array)$id)->select();
                    if (!empty($data)) {
                        foreach ($data as $k => $v) {
                            if (in_array($v['type'], ['image', 'voice'])) $this->app->material->delete($v['content']);
                        }
                    }
                    db('wechat_reply')->where('id', 'in', (array)$id)->delete();
                    return json(['code' => 1, 'msg' => '删除成功']);
                }
            }
            $where = [];
            if ($id || in_array($key, ['subscribe', 'default'])) {
                if ($id) {
                    $where[] = ['id', '=', $id];
                } else {
                    $where[] = ['key', '=', $key];
                }
                $data = db('wechat_reply')->where($where)->find();
                empty($data) && $data = [];
                if (!empty($data)) {
                    if (in_array($data['type'], ['image', 'voice'])) {
                        $data['url'] = $this->request->domain() . '/uploads/material/' . $data['content'] . '.' . $data['ext'];
                    } else {
                        $data['url'] = '';
                    }
                } else {
                    $data = [];
                }
            } else {
                $where[] = ['key', 'not in', ['subscribe', 'default']];
                $data = db('wechat_reply')->where($where)->paginate()->toArray();
            }
            return json(['code' => 1, 'data' => $data]);
        }
    }

    /**
     * 素材管理
     */
    public function material($type = 'news', $page = 1, $limit = 20, $media_id = '')
    {
        if (request()->isPost()) {

        } else {
            try {
                if ($media_id) {
                    $data = $this->app->material->get($media_id);
                } else {
                    $data = $this->app->material->list($type, ($page - 1) * $limit, $limit);
                    if ($data['item_count'] > 0) {
                        foreach ($data['item'] as $k => $v) {
                            $val = ['media_id' => $v['media_id']];
                            if ($type == 'news') {
                                $val['title'] = empty($v['content']['news_item'][0]) ? '' : $v['content']['news_item'][0]['title'];
                                $val['url'] = empty($v['content']['news_item'][0]) ? '' : $v['content']['news_item'][0]['url'];
                            } else {
                                $val['title'] = $v['name'];
                                $val['url'] = $v['url'];
                            }
                            $data['item'][$k] = $val;
                        }
                    }
                    $data = [
                        'current_page' => $page,
                        'data' => $data['item'],
                        'last_page' => ($data['item_count'] < $limit || $page * $limit == $data['total_count']) ? $page : $page + 1,
                        'per_page' => $limit,
                        'total' => $data['total_count']
                    ];
                }
                return json(['code' => 1, 'data' => $data]);
            } catch (\Exception $e) {
                return json($this->err($e->getMessage()));
            }
        }
    }

    /**
     * 上传素材
     * @return \think\response\Json
     */
    public function upload_media()
    {
        try {
            $file = request()->file();
            if (empty($file)) return json(['code' => 41006, 'msg' => '请上传文件']);
            $file_key = array_keys($file)[0];
            $extension = strtolower(pathinfo($file[$file_key]->getInfo('name'), PATHINFO_EXTENSION));
            $info = $file[$file_key]->move(\Env::get('root_path') . 'public' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'material', basename($file[$file_key]->getInfo()['tmp_name']) . '.' . $extension);
            if (!$info) return json(['code' => 41007, 'msg' => '文件上传失败:' . $file[$file_key]->getError()]);
            if (in_array($extension, ['bmp', 'png', 'jpeg', 'jpg', 'gif'])) {
                $result = $this->app->material->uploadImage($info->getPathName());
            }
            if (in_array($extension, ['mp3', 'wma', 'wav', 'amr'])) {
                $result = $this->app->material->uploadVoice($info->getPathName());
            }
            if (!empty($result['errcode'])) return json(['code' => $result['errcode'], 'msg' => $result['errmsg']]);
            cache($result['media_id'], [
                'path' => $info->getPathName(),
                'ext' => $extension,
                'name' => $info->getSaveName()
            ]);
            return json(['code' => 1, 'data' => $result]);
        } catch (\Exception $e) {
            return json($this->err($e->getMessage()));
        }
    }

    /**
     * @param array $data 处理错误返回值
     */
    public function err($msg = '')
    {
        $result = json_decode(substr($msg, strpos($msg, "{"), strrpos($msg, "}")), 1);
        if (!empty($result['errcode'])) {
            $result = ['code' => $result['errcode'], 'msg' => '出现未知错误,请检查微信配置和日志文件'];
            switch ($result['errcode']) {
                case '40164':
                    $result['msg'] = '请在微信公众平台处将当前服务器IP加入白名单';
                    break;
            }
            return $result;
        }
        return ['code' => 41008, 'msg' => $msg];
    }

    public function _empty($name)
    {
        return $this->_404();
    }

}
