<?php
// +----------------------------------------------------------------------
// | ThinkCMF [ WE CAN DO IT MORE SIMPLE ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013-present http://www.thinkcmf.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 老猫 <zxxjjforever@163.com>
// +----------------------------------------------------------------------
namespace app\admin\controller;

use app\admin\logic\AppLogic;
use app\admin\logic\PluginLogic;
use cmf\model\OptionModel;
use cmf\paginator\Bootstrap;
use think\facade\Db;


class AppStoreController extends AppStoreAdminBaseController
{
    // 应用市场服务端域名
    const APPSTORE_SERVER_URL = 'https://cmf.cooope.com';

    /**
     * 应用市场
     * @adminMenu(
     *     'name'   => '应用市场',
     *     'parent' => 'admin/Plugin/default',
     *     'display'=> true,
     *     'hasView'=> true,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '应用市场',
     *     'param'  => ''
     * )
     */
    public function apps()
    {
        $currentPage = $this->request->param('page', 1, 'intval');
        $url         = self::APPSTORE_SERVER_URL . "/api/appstore/apps?{$this->buildRequestParams(['page'=>$currentPage])}";
        $data        = cmf_curl_get($url);

        $data = json_decode($data, true);
        $page = '';

        if (empty($data['code'])) {
            $apps = [];
        } else {
            $apps      = $data['data']['apps'];
            $paginator = new Bootstrap([], 10, $currentPage, $data['data']['total'], false, ['path' => $this->request->baseUrl()]);
            $page      = $paginator->render();
        }

        $appstoreSettings = cmf_get_option('appstore_settings');


        $newApps = [];
        foreach ($apps as $mApp) {
            $mApp['installed']   = 0;
            $mApp['need_update'] = 0;
            $appName             = $mApp['name'];
            $findAppSetting      = OptionModel::where('option_name', "app_manifest_" . $appName)->find();

            if (!empty($findAppSetting)) {
                $installedApp          = $findAppSetting['option_value'];
                $mApp['installed']     = 1;
                if (version_compare($mApp['version'], $installedApp['version'], '>')) {
                    $mApp['need_update'] = 1;
                } else {
                    $mApp['need_update'] = 0;
                }
                $mApp['installed_app'] = $installedApp;
            }

            $newApps[] = $mApp;
        }

        $this->assign('apps', $newApps);
        $this->assign('appstore_settings', $appstoreSettings);


        $this->assign('page', $page);
        return $this->fetch();
    }

    /**
     * 插件市场
     * @adminMenu(
     *     'name'   => '插件市场',
     *     'parent' => 'admin/Plugin/default',
     *     'display'=> false,
     *     'hasView'=> true,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '插件市场',
     *     'param'  => ''
     * )
     */
    public function plugins()
    {
        $currentPage = $this->request->param('page', 1, 'intval');
        $url         = self::APPSTORE_SERVER_URL . "/api/appstore/plugins?{$this->buildRequestParams(['page'=>$currentPage])}";
        $data        = cmf_curl_get($url);
        $data = json_decode($data, true);
        $page = '';

        if (empty($data['code'])) {
            $plugins = [];
        } else {
            $plugins   = $data['data']['plugins'];
            $paginator = new Bootstrap([], 10, $currentPage, $data['data']['total'], false, ['path' => $this->request->baseUrl()]);
            $page      = $paginator->render();
        }

        $appstoreSettings = cmf_get_option('appstore_settings');

        $installedPlugins = Db::name('plugin')->column('*', 'name');

        $newPlugins = [];
        foreach ($plugins as $plugin) {
            $plugin['installed']   = 0;
            $plugin['need_update'] = 0;
            $pluginName            = cmf_parse_name($plugin['identifier'], 1);

            if (!empty($installedPlugins[$pluginName]) && is_dir(WEB_ROOT . 'plugins' . DIRECTORY_SEPARATOR . cmf_parse_name($plugin['identifier'], 0))) {
                $installedPlugin            = $installedPlugins[$pluginName];
                $plugin['installed']        = 1;
                if (version_compare($plugin['version'],$installedPlugin['version'], '>')) {
                    $plugin['need_update'] = 1;
                } else {
                    $plugin['need_update'] = 0;
                }
                $plugin['installed_plugin'] = $installedPlugin;
            }

            $newPlugins[] = $plugin;
        }
        $this->assign('plugins', $newPlugins);
        $this->assign('appstore_settings', $appstoreSettings);


        $this->assign('page', $page);
        return $this->fetch();
    }


    public function login()
    {
        $this->assign('domain', self::APPSTORE_SERVER_URL);
        return $this->fetch();
    }

    public function doLogin()
    {
        $accessToken = $this->request->param('access_token');
        if (empty($accessToken)) {
            $this->error(lang('illegal request'));
        }

        $httpReferer = $this->request->server('HTTP_REFERER');
        if (empty($httpReferer)) {
            $this->error(lang('illegal request'));
        }
        $httpReferer = parse_url($httpReferer);
        $domain      = empty($httpReferer['host']) ? '' : $httpReferer['host'];

        $data = cmf_curl_get(self::APPSTORE_SERVER_URL . "/api/appstore/login/refreshAccessToken?domain=$domain",[
            'XX-Device-Type:web',
            'XX-Token:'.$accessToken
        ]);
        if (empty($data)) {
            $this->error('请求失败，请重新登录！');
        }
        $data = json_decode($data, true);
        if (!empty($data['data']['access_token'])) {
            cmf_set_option('appstore_settings', $data['data']);
        }
        $this->success('登录成功！');

    }

    public function installPlugin()
    {
        $id      = $this->request->param('id', 0, 'intval');
        $version = $this->request->param('version', '');
        $data    = cmf_curl_get(self::APPSTORE_SERVER_URL . "/api/appstore/plugins/{$id}?{$this->buildRequestParams(['version'=>$version])}");
        $data    = json_decode($data, true);

        if (empty($data['code'])) {
            if (!empty($data['data']['code']) && $data['data']['code'] == 10001) {
                cmf_set_option('appstore_settings', ['access_token' => '']);
                $this->error($data['msg'], null, ['code' => 10001]);
            }

            if (!empty($data['data']['code']) && $data['data']['code'] == 10002) {
                $this->error($data['msg'], null, ['code' => 10002]);
            }

        } else {
            if (!empty($data['code']) && $data['code'] == 10008) {
                $this->error($data['msg'], null, ['code' => 10008]);
            }

            if(empty($data['data']['plugin']['file_url'])){
                $this->error('插件还未发布版本', null, ['code' => 10002]);
            }
            $tmpFileName = "plugin{$id}_" . time() . microtime() . '.zip';

            $tmpFileDir = CMF_DATA . 'download/';

            if (!is_dir($tmpFileDir)) {
                mkdir($tmpFileDir, 0777, true);
            }

            $tmpFile = $tmpFileDir . $tmpFileName;
            $fp = fopen($tmpFile, 'wb') or $this->error('操作失败！'); //新建或打开文件,将curl下载的文件写入文件

            $ch = curl_init($data['data']['plugin']['file_url']);
            curl_setopt($ch, CURLOPT_FILE, $fp);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 信任任何证书
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // 检查证书中是否设置域名
            $res = curl_exec($ch);
            curl_close($ch);
            fclose($fp);

            $pluginName = cmf_parse_name($data['data']['plugin']['name'], 0);

            $archive = new \PclZip($tmpFile);

            $files = $archive->listContent();


            foreach ($files as $mFile) {
                if (strpos($mFile['filename'], $pluginName) === 0) {
                    $result = $archive->extractByIndex($mFile['index'], PCLZIP_OPT_PATH, WEB_ROOT . 'plugins/', PCLZIP_OPT_REPLACE_NEWER);
                }
            }

            unlink($tmpFile);

            $pluginName = cmf_parse_name($pluginName, 1);

            if (empty($version)) {
                $result = PluginLogic::install($pluginName);
            } else {
                $result = PluginLogic::update($pluginName);
            }

            if ($result !== true) {
                $this->error($result);
            }

        }
        if (empty($version)) {
            $this->success('安装成功！');
        } else {
            $this->success('升级成功！');
        }
    }

    public function installApp()
    {
        $dirs = [
            realpath(CMF_ROOT . 'api') . DIRECTORY_SEPARATOR,
            realpath(CMF_ROOT . 'app') . DIRECTORY_SEPARATOR,
            realpath(CMF_ROOT . 'data') . DIRECTORY_SEPARATOR,
            realpath(WEB_ROOT . 'plugins') . DIRECTORY_SEPARATOR,
        ];

        foreach ($dirs as $dir) {
            if (!cmf_test_write($dir)) {
                $this->error('目录不可写' . $dir);
            }
        }

        $id      = $this->request->param('id', 0, 'intval');
        $version = $this->request->param('version', '');
        $data    = cmf_curl_get(self::APPSTORE_SERVER_URL . "/api/appstore/apps/{$id}?{$this->buildRequestParams(['version'=>$version])}");
        $data    = json_decode($data, true);

        if (empty($data['code'])) {
            if (!empty($data['data']['code']) && $data['data']['code'] == 10001) {
                cmf_set_option('appstore_settings', ['access_token' => '']);
                $this->error($data['msg'], null, ['code' => 10001]);
            }

            if (!empty($data['data']['code']) && $data['data']['code'] == 10002) {
                $this->error($data['msg'], null, ['code' => 10002]);
            }

        } else {

            if (!empty($data['code']) && $data['code'] == 10008) {
                $this->error($data['msg'], null, ['code' => 10008]);
            }

            if(empty($data['data']['app']['file_url'])){
                $this->error('应用还未发布版本', null, ['code' => 10002]);
            }
            $tmpFileName = "app{$id}_" . time() . microtime() . '.zip';

            $tmpFileDir = CMF_DATA . 'download/';

            if (!is_dir($tmpFileDir)) {
                mkdir($tmpFileDir, 0777, true);
            }


       
            $tmpFile = $tmpFileDir . $tmpFileName;
            $fp = fopen($tmpFile, 'wb') or $this->error('操作失败！'); //新建或打开文件,将curl下载的文件写入文件


            $ch = curl_init($data['data']['app']['file_url']);
            curl_setopt($ch, CURLOPT_FILE, $fp);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 信任任何证书
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // 检查证书中是否设置域名
            $res = curl_exec($ch);
            curl_close($ch);
            fclose($fp);

            $appName = $data['data']['app']['name'];
            $archive = new \PclZip($tmpFile);

            $files = $archive->listContent();
            if (empty($files)) {
                $this->error('文件为空');
            }
            
            foreach ($files as $mFile) {
                $result = $archive->extractByIndex($mFile['index'], PCLZIP_OPT_PATH, CMF_ROOT, PCLZIP_OPT_REMOVE_PATH, "{$data['data']['app']['name']}/", PCLZIP_OPT_REPLACE_NEWER);
            }

            unlink($tmpFile);

            if (empty($version)) {
                $result = AppLogic::install($appName);
            } else {
                $result = AppLogic::update($appName);
            }

            if ($result !== true) {
                $this->error($result);
            }

        }
        if (empty($version)) {
            $this->success('安装成功，请刷新网页！');
        } else {
            $this->success('升级成功，请刷新网页！');
        }
    }


    private function buildRequestParams($params = [])
    {
        $appStoreSettings = cmf_get_option('appstore_settings');
        $accessToken      = '';
        if (!empty($appStoreSettings['access_token'])) {
            $accessToken = $appStoreSettings['access_token'];
        }

        $mysql = Db::query("select VERSION() as version");
        $mysql = $mysql[0]['version'];
        $mysql = empty($mysql) ? '' : $mysql;

        $httpReferer = $this->request->server('HTTP_REFERER');
        if (empty($httpReferer)) {
            $this->error(lang('illegal request'));
        }
        $httpReferer = parse_url($httpReferer);
        $domain      = empty($httpReferer['host']) ? '' : $httpReferer['host'];

        return http_build_query(array_merge([
            'token'  => $accessToken,
            'cmf'    => cmf_version(),
            'tp'     => cmf_thinkphp_version(),
            'php'    => phpversion(),
            'mysql'  => $mysql,
            'domain' => $domain,
        ], $params));
    }


}
