<?php
/**
 * Created by daniel@liaodongting.com.
 * User: Daniel
 * Date: 2019/6/21
 * Time: 11:47
 */

namespace Services\Library;


use HttpCurl;
use LDB;
use Lib\FileUtil;
use Lib\Response\json;

class PluginsManager extends PluginsBase
{

    /**
     * @param $params
     * @return array
     * @throws \Exception
     */
    public function install_plugin($params)
    {
        set_time_limit(60);
        $plugin_code = $params['plugin_code'];
        $market_info = LDB::table('plugins_market_config')->first();
        if (!$market_info) return $this->error('您还没有绑定应用市场，请先进行绑定后再操作');
        $exits_info = LDB::table('plugins')->where(['plugin_code' => $plugin_code])->first();
        if ($exits_info) return $this->error('插件已经安装过，如果需要安装请先卸载已装插件', ['err' => 'installed']);
        $data = [
            'plugin_code' => $plugin_code,
            'time' => time(),
            'app_key' => $market_info['app_key'],
            'referer' => get_host('weidogsadmin/system/plugins.html?action=install'),
        ];
        $token = $market_info['app_secret'];
        $sign = up_make_sign($data, $token);
        $data['sign'] = $sign;
        $result = HttpCurl::post($this->update_host . '/?r=api/update/install-plugins', $data);

        $re = json_decode($result, true);

        if (!$re) {
            if (is_string($result) && !empty($result)) {
                return $this->error("请求出现错误：" . $result);
            }
            return $this->error('请求出现错误');
        } elseif ($re['status'] !== 'success') {

            return $this->error("更新服务器返回错误信息：" . ($re['message'] ? $re['message'] : $re['msg']), $re);
        } else {
            $data = $re['data'];
            $config = $data['config'];
            if($config['install_type']===1){

                return $this->install_old_plugin($data,$token);#全局插件安装
            }else{
                return $this->install_common_plugin($data,$token);#普通插件安装
            }
        }
    }

    private function install_common_plugin(array $data,$token){
        $config = $data['config'];
        $file_info = $data['file_info'];
        $file_raw = base64_decode($file_info['raw']);//文件进行解密
        $temp_path = pub_path('template_path');
        $file_name = $file_info['file_name'];
        is_dir($temp_path) or mkdir($temp_path, 0777, true);
        $file_path = $temp_path . '/' . $file_name;
        is_dir(dirname($file_path)) or mkdir(dirname($file_path), 0777, true);
        file_put_contents($file_path, $file_raw);
        $plugin_dir = ucfirst(camelize($config['plugin_code']));//实际目录转换成驼峰风格 并且首字母大写
        $addons_path = APP_PATH . '/Addons';
        $plugin_path = $addons_path . '/' . $plugin_dir;
        $zipPath = $plugin_path;
        //解压失败
        $zipFile = new \Lib\PclZip($file_path);

        foreach ($zipFile->listContent() as $item) {

            if (strpos($item['filename'], $plugin_dir . '/') === 0) {
                $zipPath = $addons_path;

                break;
            }
        }
        try {
            $re = $zipFile->extract(PCLZIP_OPT_PATH, $zipPath, PCLZIP_OPT_REPLACE_NEWER);


            if (!$re) return $this->error('解压失败:' . $zipFile->error_string);
        } catch (\Exception $e) {
            return $this->error('插件解压失败，错误信息：' . $e->getMessage());
        }

        $plugin_data = [
            'plugin_code' => $config['plugin_code'],
            'plugin_name' => $config['plugin_name'],
            'version' => $config['version'],
            'author' => $config['author'],
            'plugin_desc' => $config['desc'],
            'create_time' => time(),
        ];
        LDB::table('plugins')->insert($plugin_data);
        if (file_exists($plugin_path . '/install.sql')) {
            $sql = file_get_contents($plugin_path . '/install.sql');
            $re = $this->updateRunSql($sql);
            if ($re['status'] !== 'success') {
                \Log::error('安装插件' . $config['plugin_code'] . '出现错误:' . $re['msg']);
//                return error($re['msg']);
            }
        }
        //发布静态资源
        if (is_dir($plugin_path . '/static')) {
            \Lib\FileUtil::getInstance()->copyDir($plugin_path . '/static', pub_path('Addons/' . $plugin_dir . '/static'), true);
        }

        unlink($file_path);
        return $this->success('安装成功');
    }

    /**
     * @param array $data
     * @param $token
     * @return array
     * @throws \Exception
     */
    private function install_old_plugin(array $data,$token){
        $config = $data['config'];
        $file_info = $data['file_info'];
        $file_raw = base64_decode($file_info['raw']);//文件进行解密
        $temp_path = pub_path('template_path');
        $file_name = $file_info['file_name'];
        is_dir($temp_path) or mkdir($temp_path, 0777, true);
        $file_path = $temp_path . '/' . $file_name;
        is_dir(dirname($file_path)) or mkdir(dirname($file_path), 0777, true);
        file_put_contents($file_path, $file_raw);
        $plugin_path = ROOT_PATH;
        $zipPath = $plugin_path;
        $zipFile = new \Lib\PclZip($file_path);
        $app_dir_check=0;
        foreach ($zipFile->listContent() as $item) {

            if (strpos($item['filename'], basename(APP_PATH) . '/') === 0) {
                $app_dir_check=1;

                break;
            }
        }
        if(!$app_dir_check){
            return $this->error('应用目录检测失败，请确认目录结构是否合理');
        }
        try {
            $re = $zipFile->extract(PCLZIP_OPT_PATH, $zipPath, PCLZIP_OPT_REPLACE_NEWER);


            if (!$re) return $this->error('解压失败:' . $zipFile->error_string);
        } catch (\Exception $e) {
            return $this->error('插件解压失败，错误信息：' . $e->getMessage());
        }

        $plugin_data = [
            'plugin_code' => $config['plugin_code'],
            'plugin_name' => $config['plugin_name'],
            'version' => $config['version'],
            'author' => $config['author'],
            'plugin_desc' => $config['desc'],
            'create_time' => time(),
            'install_type' =>$config['install_type']
        ];
        LDB::table('plugins')->insert($plugin_data);
        $sql_file=$plugin_path . '/install.sql';
        if (file_exists($sql_file)) {
            $sql = file_get_contents($sql_file);
            $re = $this->updateRunSql($sql);
            if ($re['status'] !== 'success') {
                \Log::error('安装插件' . $config['plugin_code'] . '出现错误:' . $re['msg']);
//                return error($re['msg']);
            }
            @unlink($sql_file);
        }
        unlink($file_path);
        return $this->success('安装成功');
    }

    /**
     * 卸载插件
     * @param array $params
     * @return array
     * @throws \Exception
     */
    public function uninstall_plugin(array $params)
    {
        $error = [];
        $plugin_code = $params['plugin_code'];
        $market_info = LDB::table('plugins_market_config')->first();
        if (!$market_info) return $this->error('您还没有绑定应用市场，请先进行绑定后再操作');
        $exits_info = LDB::table('plugins')->where(['plugin_code' => $plugin_code])->first();
        if (!$exits_info) {
            return $this->error('待卸载插件不存在');
        }
        if($exits_info['install_type']===1){
            return $this->error('该插件不支持卸载');
        }
        $plugin_dir = camelize($exits_info['plugin_code']);
        $plugin_path = DOXCX_FRAME_PATH . 'Addons/' . $plugin_dir;
        if (!is_dir($plugin_path)) {
            $error[] = '插件卸载-插件目录不存在';
        }
        //执行卸载sql
        if (file_exists($plugin_path . '/uninstall.sql')) {
            $sql = file_get_contents($plugin_path . '/uninstall.sql');
            $re = $this->updateRunSql($sql);
            if ($re['status'] !== 'success') {
                \Log::error('卸载插件' . $plugin_code . '出现错误:' . $re['msg']);
//                return error($re['msg']);
            }
        }
        //删除 发布过的静态资源
        $static_path = pub_path('Addons/' . $plugin_dir );
        if (is_dir($static_path)) {
            FileUtil::getInstance()->unlinkDir($static_path);
        }

        $delRe = LDB::table('plugins')->where(['plugin_code' => $plugin_code])->delete();
        if (!$delRe)$error[] = '插件卸载-插件数据不存在';
        FileUtil::getInstance()->unlinkDir($plugin_path);
        if(!empty($error)){
            return $this->error(end($error));
        }else{
            return $this->success('插件成功');
        }



    }

    /**
     * 更新插件
     * @param array $params
     * @return array
     * @throws \Exception
     */
    public function  update_plugin(array $params){
        $plugin_code = $params['plugin_code'];
        $market_info = LDB::table('plugins_market_config')->first();
        if (!$market_info) return $this->error('您还没有绑定应用市场，请先进行绑定后再操作');
        $exits_info = LDB::table('plugins')->where(['plugin_code' => $plugin_code])->first();
        if (!$exits_info) return $this->error('请先安装插件再进行操作');
        $data = [
            'plugin_code' => $plugin_code,
            'time' => time(),
            'app_key' => $market_info['app_key'],
            'current_version'=>$exits_info['version']
        ];
        $token = $market_info['app_secret'];
        $sign = up_make_sign($data, $token);
        $data['sign'] = $sign;
        $result = HttpCurl::post($this->update_host . '/?r=api/update/update-plugins', $data);

        $re = json_decode($result, true);

        if (!$re) {
            if (is_string($result) && !empty($result)) {
                return $this->error("请求出现错误：" . $result);
            }
            return $this->error('请求出现错误');
        } elseif ($re['status'] !== 'success') {

            return $this->error("更新服务器返回错误信息：" . ($re['message'] ? $re['message'] : $re['msg']), $re);
        } else {
            $data = $re['data'];
            $config = $data['config'];
            if($config['update_type']===1){

                return $this->update_old_plugin($data,$token,$exits_info);#全局插件安装
            }else{
                return $this->update_common_plugin($data,$token,$exits_info);#普通插件安装
            }
        }
    }

    /**
     * 更新普通插件
     * @param array $data
     * @param $token
     * @param $exits_info
     * @return array
     * @throws \Exception
     */
    private function update_common_plugin(array $data,$token,$exits_info){
        $config = $data['config'];
        $file_info = $data['file_info'];
        $file_raw = decode($file_info['raw'], up_make_sign($config, $token));//文件进行解密
        $temp_path = pub_path('template_path');
        $file_name = $file_info['file_name'];
        is_dir($temp_path) or mkdir($temp_path, 0777, true);
        $file_path = $temp_path . '/' . $file_name;
        is_dir(dirname($file_path)) or mkdir(dirname($file_path), 0777, true);
        file_put_contents($file_path, $file_raw);
        $plugin_dir = ucfirst(camelize($config['plugin_code']));//实际目录转换成驼峰风格 并且首字母大写
        $addons_path = APP_PATH . '/Addons';
        $plugin_path = $addons_path . '/' . $plugin_dir;
        $zipPath = $plugin_path;
        //解压失败
        $zipFile = new \Lib\PclZip($file_path);

        foreach ($zipFile->listContent() as $item) {

            if (strpos($item['filename'], $plugin_dir . '/') === 0) {
                $zipPath = $addons_path;

                break;
            }
        }
        if(!is_dir($plugin_path)){
            return  $this->error('安装失败，插件目录不存在');
        }
        try {
            $re = $zipFile->extract(PCLZIP_OPT_PATH, $zipPath, PCLZIP_OPT_REPLACE_NEWER);


            if (!$re) return $this->error('解压失败:' . $zipFile->error_string);
        } catch (\Exception $e) {
            return $this->error('插件解压失败，错误信息：' . $e->getMessage());
        }

        $plugin_data = [

            'version' => $config['version'],
            'edit_time' => time(),
        ];
        LDB::table('plugins')->where(['plugin_code'=>$exits_info['plugin_code']])->update($plugin_data);
        if (file_exists($plugin_path . '/update.sql')) {
            $sql = file_get_contents($plugin_path . '/update.sql');
            $re = $this->updateRunSql($sql);
            if ($re['status'] !== 'success') {
                \Log::error('更新插件' . $config['plugin_code'] . '出现错误:' . $re['msg']);
//                return error($re['msg']);
            }
            @unlink($plugin_path . '/update.sql');
        }
        //重新发布静态资源
        if (is_dir($plugin_path . '/static')) {
            \Lib\FileUtil::getInstance()->copyDir($plugin_path . '/static', pub_path('Addons/' . $plugin_dir . '/static'), true);
        }

        unlink($file_path);
        return $this->success('成功更新到 v'.$config['version'].'版本');
    }

    /**
     * 更新全局安装插件
     * @param array $data
     * @param $token
     * @param $exits_info
     * @return array
     * @throws \Exception
     */
    private function update_old_plugin(array $data,$token,$exits_info){
        $config = $data['config'];
        $file_info = $data['file_info'];
        $file_raw = decode($file_info['raw'], up_make_sign($config, $token));//文件进行解密
        $temp_path = pub_path('template_path');
        $file_name = $file_info['file_name'];
        is_dir($temp_path) or mkdir($temp_path, 0777, true);
        $file_path = $temp_path . '/' . $file_name;
        is_dir(dirname($file_path)) or mkdir(dirname($file_path), 0777, true);
        file_put_contents($file_path, $file_raw);
        $plugin_path = ROOT_PATH;
        $zipPath = $plugin_path;
        $zipFile = new \Lib\PclZip($file_path);
        $app_dir_check=0;
        foreach ($zipFile->listContent() as $item) {

            if (strpos($item['filename'], basename(APP_PATH) . '/') === 0) {
                $app_dir_check=1;

                break;
            }
        }
        if(!$app_dir_check){
            return $this->error('应用目录检测失败，请确认目录结构是否合理');
        }
        try {
            $re = $zipFile->extract(PCLZIP_OPT_PATH, $zipPath, PCLZIP_OPT_REPLACE_NEWER);


            if (!$re) return $this->error('解压失败:' . $zipFile->error_string);
        } catch (\Exception $e) {
            return $this->error('插件解压失败，错误信息：' . $e->getMessage());
        }

        $plugin_data = [
            'version' => $config['version'],
            'edit_time' => time(),
        ];
        LDB::table('plugins')->where(['plugin_code'=>$exits_info['plugin_code']])->update($plugin_data);
        $sql_file=$plugin_path . '/update.sql';
        if (file_exists($sql_file)) {
            $sql = file_get_contents($sql_file);
            $re = $this->updateRunSql($sql);
            if ($re['status'] !== 'success') {
                \Log::error('更新插件' . $config['plugin_code'] . '出现错误:' . $re['msg']);
//                return error($re['msg']);
            }
            @unlink($sql_file);
        }
        unlink($file_path);
        return $this->success('成功更新到 v'.$config['version'].'版本');
    }
}