<?php
namespace app\bsadmin\controller;
use think\facade\View;
use think\facade\Cache;
use think\facade\Db;
use helper\URL;
use helper\Dir;

class Packages extends Base
{
    public function index()
    {
        if (request()->isAjax()) {
            $Data=Dir::tree(root_path().'VERSION/system');
            if (!empty($Data))
                $Data=arraySort($Data,'filename',SORT_DESC);
            foreach ($Data as $k => $v) {
                $Data[$k]['path']=str_replace(root_path(),'',$v['path']);
                $Data[$k]['filename']=intval($v['filename']);
                $Data[$k]['create_time']=date('Y/m/d H:i:s',$v['filemtime']);
                $Data[$k]['update_time']=date('Y/m/d H:i:s',$v['fileatime']);
                $Data[$k]['backup']=@file_exists($v['path'].'backup.zip');
                $Data[$k]['step']=@file_exists($v['path'].'step.zip');
                $Data[$k]['log']=@file_get_contents($v['path'].'install.log');
                $changelist=@file_get_contents($v['path'].'changelist.list');
                if($changelist)
                    $Data[$k]['changelist']=explode("\n",$changelist);
            }
            return $this->ajaxReturn('',0,$Data);
        }else{
            $SystemInfo=@file_get_contents(root_path()."VERSION/version.json");
            View::assign('SystemInfo',$SystemInfo);
            return View::fetch();
        }
    }
    public function inspectSystemVersion()
    {
        $Data=$this->updateSystemVersionInfo();
        if($Data && gettype($Data)=='array'){
            return $this->ajaxReturn($Data['msg'],$Data['code'],$Data['data']);
        }else{
            return $this->ajaxReturn($Data,-100);
        }
    }
    public function updateSystemVersion()
    {
        $SystemInfo=$this->getSystemFileVersionInfo();
        if($SystemInfo){
            $key=config('xy_xycms.key');
            if($key){
                $ret=URL::post($SystemInfo['update_url'].'/'.$SystemInfo['down_url'].'/'.$key,json_encode($SystemInfo,JSON_UNESCAPED_UNICODE));
                $Data=json_decode($ret,true);
                $filePath=root_path().'VERSION/system/'.$Data['data']['version_code'].'/step.zip';
                if($Data['code']==600){
                    $this->downloadPackage($Data['data']['package_url'],$filePath);
                    $installRet=$this->installPackage($filePath);
                    if($installRet===true){
                        $Data['data']['time']=date('Y/m/d H:i:s');
                        $this->insertPackagesSystemInfo($Data['data']);
                        $this->callbackInstallVersionInfo();
                        return $this->ajaxReturn('安装成功');
                    }else{
                        return $this->ajaxReturn($installRet,-100);
                    }
                }else{
                    return $this->ajaxReturn($Data['msg'],$Data['code']);
                }
            }else{
                return '系统->配置->新云Cloud->应用KEY为空';
            }
        }else{
            return $this->ajaxReturn('版本信息文件不存在',-100);
        }
    }
    public function updateSystemVersionInfo()
    {
        $Data=$this->getSystemVersionInfo();
        if(gettype($Data)=='array'&&!empty($Data))
            $this->insertPackagesSystemInfo($Data['data']);
        return $Data;
    }
    public function getSystemVersionInfo()
    {
        $SystemInfo=$this->getSystemFileVersionInfo();
        if($SystemInfo){
            $key=config('xy_xycms.key');
            if($key){
                $ret=URL::post($SystemInfo['update_url'].'/getSystemInfo/'.$key,json_encode($SystemInfo,JSON_UNESCAPED_UNICODE));
                return json_decode($ret,true);
            }else{
                return '系统->第三方->新云Cloud->应用KEY为空';
            }
        }else{
            return '版本信息文件不存在';
        }
    }
    public function getSystemFileVersionInfo()
    {
        $filePath=root_path()."VERSION/version.json";
        if(@file_exists($filePath)){
            $SystemInfo=file_get_contents($filePath);
            return json_decode($SystemInfo,true);
        }else{
            return false;
        }
    }
    public function downloadPackage($url,$filePath)
    {
        if (@file_exists(dirname($filePath)))
            Dir::del(dirname($filePath));
        mkdir(dirname($filePath), 0777, true);
        if(@file_exists($filePath))
            @unlink($filePath);
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $content = curl_exec($ch);
        @file_put_contents($filePath, $content);
        curl_close($ch);
        return true;
    }
    protected function insertPackagesSystemInfo($data)
    {
        try {
            //写入配置文件
            $jsonPath=root_path()."VERSION/version.json";
            $jsonFile = fopen($jsonPath, "w") or die("Unable to open file!");
            fwrite($jsonFile, json_encode($data,JSON_UNESCAPED_UNICODE));
            fclose($jsonFile);
            return true;
        } catch (Exception $e) {
            return false;
        }
    }
    protected function installPackage($filename)
    {
        if(!$this->extractPackage($filename))
            return '安装包解压失败';
        $path=dirname($filename);
        file_put_contents($path.'/install.log',"创建安装日志文件\n",FILE_APPEND);
        if(file_exists($path.'/packages.zip')){
            file_put_contents($path.'/install.log',"准备备份\n",FILE_APPEND);
            $zip = new \ZipArchive;
            if($zip->open($path.'/packages.zip')===TRUE){
                $backuplist=[];
                for ($i = 0; $i < $zip->numFiles; $i++) {
                    $filename=$zip->getNameIndex($i);
                    if(is_file(root_path().$filename)){
                        $backuplist[]=$filename;
                        file_put_contents($path.'/install.log',$filename."\n",FILE_APPEND);
                    }
                }
                if(empty($backuplist)){
                    file_put_contents($path.'/install.log',"无需备份\n",FILE_APPEND);
                }else{
                    file_put_contents($path.'/install.log','备份'.count($backuplist)."个文件\n",FILE_APPEND);
                    file_put_contents($path.'/install.log',"开始备份\n",FILE_APPEND);
                    $backupRet=$this->backupFile($path,$backuplist);
                    if($backupRet===true){
                        file_put_contents($path.'/install.log',"备份成功\n",FILE_APPEND);
                    }else{
                        file_put_contents($path.'/install.log',$backupRet."\n",FILE_APPEND);
                    }
                }
                $zip->close();
            }else{
            file_put_contents($path.'/install.log',"创建备份文件失败\n",FILE_APPEND);
            }
        }
        file_put_contents($path.'/install.log',"检查是否更新H5\n",FILE_APPEND);
        if (file_exists($path.'/updateH5.lock')) {
            file_put_contents($path.'/install.log',"H5有更新\n",FILE_APPEND);
            if(is_dir('./static/default/mobile/static')){
                if (is_dir('./static/default/mobile/static.back'))
                    Dir::del('./static/default/mobile/static.back');
                rename('./static/default/mobile/static','./static/default/mobile/static.back');
            }
        }else{
            file_put_contents($path.'/install.log',"H5无更新\n",FILE_APPEND);
        }
        file_put_contents($path.'/install.log',"开始安装更新文件\n",FILE_APPEND);
        if($this->extractPackage($path.'/packages.zip',root_path())){
            file_put_contents($path.'/install.log',"安装成功，检查数据库更新\n",FILE_APPEND);
            if (file_exists($path.'/database.sql')) {
                file_put_contents($path.'/install.log',"数据库更新开始\n",FILE_APPEND);
                $sql=@file_get_contents($path.'/database.sql');
                $sql=str_replace('{$database.prefix}',config('database.connections.mysql.prefix'),$sql);
                foreach (explode("\n",$sql) as $k => $v) {
                    try {
                        if(trimall($v)){
                            Db::query($v);
                            file_put_contents($path.'/install.log',$v."=====ok\n",FILE_APPEND);
                        }
                    } catch (\think\db\exception\PDOException $e) {
                        file_put_contents($path.'/install.log',$v."=====fial\n".$e->getMessage()."\n",FILE_APPEND);
                    }
                }
            }
            if (file_exists($path.'/DatabaseSql.php')) {
                file_put_contents($path.'/install.log',"数据库热更新开始\n",FILE_APPEND);
            	include_once $path.'/DatabaseSql.php';
                $DatabaseSql=new \DatabaseSql;
                $DatabaseSql->path=$path;
                $DatabaseSql->run();
            }
            file_put_contents($path.'/install.log',"安装结束\n",FILE_APPEND);
            return true;
        }else{
            if($this->extractPackage($path.'/backup.zip',root_path())){
                file_put_contents($path.'/install.log',"安装失败，回滚成功\n",FILE_APPEND);
                return '安装失败';
            }else{
                file_put_contents($path.'/install.log',"安装失败，且回滚失败\n",FILE_APPEND);
                return '安装失败，且回滚失败';
            }
        }
    }
    protected function extractPackage($filename,$extractTo='')
    {
        if (!file_exists($filename))
            return true;
        $zip = new \ZipArchive();
        $path=dirname($filename);
        if ($zip->open($filename) === true) {
            $zip->extractTo($extractTo?$extractTo:$path);
            $zip->close();
            return true;
        } else {
            return false;
        }
    }
    protected function backupFile($path,$backuplist)
    {
        $filename=$path.'/backup.zip';
        if(file_exists($filename))
            unlink($filename);
        $zip = new \ZipArchive;
        if($zip->open($filename,\ZIPARCHIVE::CREATE)!==TRUE){
            return '无法打开备份，或者备份创建失败';
        }
        foreach ($backuplist as $k => $v) {
            if(file_exists(root_path().$v)){
                $zip->addFile(root_path().$v,str_replace(root_path(),'',$v));
            }
        }
        $zip->addFile(root_path()."VERSION/version.json",str_replace(root_path(),'',root_path()."VERSION/version.json"));
        $zip->close();
        return true;
    }
    public function rollBackup($filename)
    {
        $filename=root_path().'VERSION/system/'.$filename.'/backup.zip';
        $installRet=$this->extractPackage($filename,root_path());
        if($installRet===true){
            return $this->ajaxReturn('成功');
        }else{
            return $this->ajaxReturn($installRet,-100);
        }
    }
    public function installPackageAjax($filename)
    {
        $filename=root_path().'VERSION/system/'.$filename.'/step.zip';
        $installRet=$this->installPackage($filename);
        if($installRet===true){
            $this->callbackInstallVersionInfo();
            return $this->ajaxReturn('成功');
        }else{
            return $this->ajaxReturn($installRet,-100);
        }
    }
    public function delInstallPackage($filename)
    {
        $filename=root_path().'VERSION/system/'.$filename.'/step.zip';
        if (@unlink($filename)) {
            return $this->ajaxReturn();
        }else{
            return $this->ajaxReturn('删除失败，请手动删除',-100);
        }
    }

    public function callbackInstallVersionInfo()
    {
        $Data=$this->getSystemFileVersionInfo();
        if ($Data) {
            $Data['key']=config('xy_xycms.key');
            $Data['key_decode']=1;
            unset($Data['log']);
            $ret =URL::post($Data['website'].'/download/callbackInstallVersionInfo',json_encode($Data));
            if ($ret)
                $ret=json_decode($ret,true);
            return $ret;
        }
        return false;
    }
}
