<?php

namespace app\admin\controller;

use app\admin\controller\base\Permissions;
use databackup\src\Backup;
use think\Env;
use think\Request;
use think\Session;

/**
 * 备份大数据，还原时间太长，效率太差
 * Class Databackup
 * @package app\admin\controller
 */
class Databackup extends Permissions
{
    /** @var Backup */
    private static $sdk;

    const DEFAULT_PATH = RUNTIME_PATH . 'backup' . DS;

    protected function _initialize()
    {
        parent::_initialize();

        $path = Env::get('data_backup_path', '');
        $path = empty($path) ? self::DEFAULT_PATH : (endWith($path, DS) ? $path : $path . DS);

        self::$sdk = new Backup([
            'path' => $path
        ]);
    }

    /**
     * table列表
     * @return mixed
     */
    public function index()
    {
        return $this->fetch('index', ['list' => self::$sdk->dataList()]);
    }

    /**
     * 备份文件列表
     * @return mixed
     */
    public function importlist()
    {
        return $this->fetch('importlist', ['list' => self::$sdk->fileList()]);
    }

    /**
     * 还原数据
     * @param int $time
     * @param null $part
     * @param null $start
     */
    public function import($time = 0, $part = null, $start = null)
    {
        if (is_numeric($time) && is_null($part) && is_null($start)) {
            $list = self::$sdk->getFile('timeverif', $time);
            if (is_array($list)) {
                session::set('backup_list', $list);
                $this->success('初始化完成！', '', array('part' => 1, 'start' => 0));
            } else {
                $this->error('备份文件可能已经损坏，请检查！');
            }
        } else if (is_numeric($part) && is_numeric($start)) {

            $list = session::get('backup_list');
            $start = self::$sdk->setFile($list)->import($start);

            if (false === $start) {
                $this->error('还原数据出错！');
            } elseif (0 === $start) {
                if (isset($list[++$part])) {
                    $data = array('part' => $part, 'start' => 0);
                    $this->success("正在还原...#{$part}", '', $data);
                } else {
                    session::delete('backup_list');
                    $this->success('还原完成！');
                }
            } else {
                $data = array('part' => $part, 'start' => $start[0]);
                if ($start[1]) {
                    $rate = floor(100 * ($start[0] / $start[1]));
                    $this->success("正在还原...#{$part} ({$rate}%)", '', $data);
                } else {
                    $data['gz'] = 1;
                    $this->success("正在还原...#{$part}", '', $data);
                }
                $this->success("正在还原...#{$part}", '');
            }
        } else {
            $this->error('参数错误！');
        }
    }

    /**
     * 删除备份文件
     */
    public function del($time = 0)
    {
        if (self::$sdk->delFile($time)) {
            $this->success("备份文件删除成功！", 'admin/databackup/importlist');
        } else {
            $this->error("备份文件删除失败，请检查权限！");
        }
    }

    /**
     * 备份表 - 命令行
     */
    public function backup()
    {
        $tables = $this->request->param('tables');
        if ($tables && $this->request->isCli()) {
            if ("all" === $tables) {
                $tables = [];
                foreach (self::$sdk->dataList() as $item) {
                    $tables[] = $item['name'];
                }
            } else {
                $tables = explode(',', $tables);
            }
            //lock
            $fileinfo = self::$sdk->getFile();
            $lock = "{$fileinfo['filepath']}backup.lock";
            !is_file($lock) || $this->error('检测到有一个备份任务正在执行，请稍后再试！');
            is_writeable($fileinfo['filepath']) || $this->error('备份目录不存在或不可写，请检查后重试！');
            file_put_contents($lock, time());
            //
            $file = $fileinfo['file'];
            self::$sdk->Backup_Init() || $this->error('初始化失败，备份文件创建失败！');
            foreach ($tables as $tablename) {
                $start = self::$sdk->setFile($file)->backup($tablename, 0);
                if (false === $start) {
                    $this->error($tablename . '备份出错！');
                } else {
                    while (is_array($start)) {
                        $start = self::$sdk->setFile($file)->backup($tablename, $start[0]);
                    }
                }
            }
            unlink($lock);
            $this->success('备份完成！');
        }
        $this->error('参数错误！');
    }

    /**
     * 备份表
     */
    public function export()
    {
        if (Request::instance()->isPost()) {
            $input = input('post.');
            $fileinfo = self::$sdk->getFile();
            $lock = "{$fileinfo['filepath']}backup.lock";
            !is_file($lock) || $this->error('检测到有一个备份任务正在执行，请稍后再试！');
            is_writeable($fileinfo['filepath']) || $this->error('备份目录不存在或不可写，请检查后重试！');
            file_put_contents($lock, time());
            //缓存锁文件
            session::set('lock', $lock);
            //缓存备份文件信息
            session::set('backup_file', $fileinfo['file']);
            //缓存要备份的表
            session::set('backup_tables', $input['tables']);
            //创建备份文件
            if (false !== self::$sdk->Backup_Init()) {
                $first_table_name = $input['tables'][0]??'null';
                $this->success('初始化成功！', '', ['tab' => ['id' => 0, 'start' => 0, 'tablename' => $first_table_name]]);
            } else {
                $this->error('初始化失败，备份文件创建失败！');
            }
        } else if (Request::instance()->isGet()) {
            $tables = session::get('backup_tables');
            $file = session::get('backup_file');
            $id = input('id');
            $start = input('start');
            $tablename = $tables[$id];
            $start = self::$sdk->setFile($file)->backup($tablename, $start);
            if (false === $start) {
                $this->error($tablename . '备份出错！');
            } else {
                while (is_array($start)) {
                    $start = self::$sdk->setFile($file)->backup($tablename, $start[0]);
                }
                if (0 === $start) {
                    if (isset($tables[++$id])) {
                        $tab = ['id' => $id, 'start' => 0, 'tablename' => $tables[$id]];//下一个递归信息
                        $this->success($tablename . '备份完成！', '', array('tab' => $tab));
                    } else {
                        //备份完成，清空缓存
                        unlink(session::get('lock'));
                        Session::delete('backup_tables');
                        Session::delete('backup_file');
                        $this->success($tablename . '备份完成！');
                    }
                } else {
                    $this->error($tablename . '备份出错！');
                }
            }
        } else {
            $this->error('参数错误！');
        }
    }

    /**
     * 修复表
     * @param null $tables
     */
    public function repair($tables = null)
    {
        if (self::$sdk->repair($tables)) {
            $this->success("数据表修复完成！");
        } else {
            $this->error("数据表修复出错请重试");
        }
    }

    /**
     * 优化表
     * @param null $tables
     */
    public function optimize($tables = null)
    {
        if (self::$sdk->optimize($tables)) {
            $this->success("数据表优化完成！");
        } else {
            $this->error("数据表优化出错请重试！");
        }
    }
}