<?php
/**
 * 炎酷CMS - 在线升级管理页
 * 流程：检查更新（异步）→ 文件对比 → 一键升级（后台异步任务，自动备份数据库+全站文件）→ 轮询任务进度
 */
define('YKCMS', 1);
require dirname(__DIR__) . '/inc/auth.php';
require dirname(__DIR__) . '/inc/upgradelib.php';

$page_title = '在线升级';
$active = 'upgrade';

// 保存升级服务器地址（唯一保留的同步写操作）
if ($_SERVER['REQUEST_METHOD'] === 'POST' && (isset($_POST['do']) ? $_POST['do'] : '') === 'save_url') {
    csrf_check();
    $url = trim(isset($_POST['upgrade_url']) ? $_POST['upgrade_url'] : '');
    if ($url !== '' && !yk_url_safe($url)) {
        flash_set('升级服务器地址不合法，仅允许 http/https', 'err');
    } else {
        config_set('upgrade_url', $url);
        admin_log('在线升级', '设置升级服务器地址:' . $url);
        flash_set('升级服务器地址已保存');
    }
    header('Location: upgrade.php');
    exit;
}

$curVersion = yk_version_get();
$upgradeUrl = site_config('upgrade_url', 'https://api.dinyun.cn/upgrade/manifest.json');

require dirname(__DIR__) . '/inc/header.php';
?>
<style>
.yk-upg-progress{height:10px;background:#eef1f6;border-radius:6px;overflow:hidden;margin:10px 0 6px}
.yk-upg-progress i{display:block;height:100%;width:0;background:linear-gradient(90deg,#3b82f6,#2563eb);border-radius:6px;transition:width .4s}
.yk-upg-log{background:#0f172a;color:#a5c8ff;border-radius:8px;padding:14px 18px;font-size:12.5px;line-height:1.9;max-height:280px;overflow-y:auto;font-family:Consolas,Menlo,monospace;white-space:pre-wrap;word-break:break-all}
.yk-upg-step{color:#5c6a7d;font-size:13px;margin-bottom:6px}
</style>

<div class="yk-card">
  <h3>版本信息</h3>
  <div class="yk-form">
    <div class="row"><label>当前版本</label><div class="ipt" style="padding-top:7px"><b style="color:#1e6fff" id="curVer"><?php echo e($curVersion); ?></b><span style="color:#999;font-size:12px;margin-left:10px">版本号保存于 config/version.php</span></div></div>
  </div>
  <form class="yk-form" method="post" action="upgrade.php">
    <?php echo csrf_field(); ?>
    <input type="hidden" name="do" value="save_url">
    <div class="row"><label>升级服务器地址</label><div class="ipt">
      <input type="text" name="upgrade_url" value="<?php echo e($upgradeUrl); ?>" placeholder="https://api.dinyun.cn/upgrade/manifest.json">
      <div class="tip">返回 JSON manifest：{"version":"1.0.1","changelog":"...","files":[{"path":"public/index.php","url":"...","md5":"..."}],"sql":["ALTER ..."]}（SQL 支持 {pre} 表前缀占位符）</div>
    </div></div>
    <div class="row"><label></label><div class="ipt"><button class="yk-btn" type="submit">保存地址</button></div></div>
  </form>
</div>

<div class="yk-card">
  <h3>检查更新</h3>
  <p style="margin-bottom:14px">
    <button class="yk-btn" type="button" id="btnCheck">检查更新</button>
    <span style="color:#999;font-size:12px;margin-left:10px">升级前将自动备份数据库与全站文件到 data/backup/，失败自动回滚</span>
  </p>
  <div id="checkResult"></div>
</div>

<div class="yk-card" id="taskCard" style="display:none">
  <h3>升级进度</h3>
  <div class="yk-upg-step" id="taskStep">准备中…</div>
  <div class="yk-upg-progress"><i id="taskBar"></i></div>
  <div style="color:#999;font-size:12px;margin-bottom:10px"><span id="taskPct">0</span>%</div>
  <div class="yk-upg-log" id="taskLog"></div>
</div>

<script>
(function(){
  var CSRF = <?php echo json_encode(csrf_token()); ?>;
  var API  = '<?php echo e(ADMIN_URL); ?>/api/upgrade.php';
  var TASK = '<?php echo e(ADMIN_URL); ?>/api/tasks.php';

  function post(act, cb){
    var xhr = new XMLHttpRequest();
    xhr.open('POST', API, true);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.onreadystatechange = function(){
      if (xhr.readyState === 4) {
        var d = null;
        try { d = JSON.parse(xhr.responseText); } catch (e) {}
        cb(d || {ok:0, msg:'服务器返回异常（HTTP ' + xhr.status + '）'});
      }
    };
    xhr.send('act=' + act + '&csrf_token=' + encodeURIComponent(CSRF));
  }

  function esc(s){ return String(s).replace(/[&<>"']/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]; }); }

  var timer = null;
  function poll(id){
    if (timer) clearInterval(timer);
    timer = setInterval(function(){
      var xhr = new XMLHttpRequest();
      xhr.open('GET', TASK + '?id=' + encodeURIComponent(id), true);
      xhr.onreadystatechange = function(){
        if (xhr.readyState !== 4) return;
        var d = null;
        try { d = JSON.parse(xhr.responseText); } catch (e) {}
        if (!d || !d.ok) return;
        document.getElementById('taskCard').style.display = '';
        document.getElementById('taskStep').textContent = d.step;
        document.getElementById('taskBar').style.width = d.progress + '%';
        document.getElementById('taskPct').textContent = d.progress;
        document.getElementById('taskLog').textContent = (d.log || []).join('\n');
        var logEl = document.getElementById('taskLog');
        logEl.scrollTop = logEl.scrollHeight;
        if (d.status === 'done' || d.status === 'error') {
          clearInterval(timer); timer = null;
          if (d.status === 'done') document.getElementById('curVer').textContent = d.step === '升级完成' ? (d.log.join(' ').match(/升级完成：(\S+)/) || [,''])[1] : document.getElementById('curVer').textContent;
        }
      };
      xhr.send();
    }, 1500);
  }

  document.getElementById('btnCheck').addEventListener('click', function(){
    var box = document.getElementById('checkResult');
    this.disabled = true; this.textContent = '检查中…';
    box.innerHTML = '';
    post('check', function(d){
      var btn = document.getElementById('btnCheck');
      btn.disabled = false; btn.textContent = '检查更新';
      if (!d.ok) { box.innerHTML = '<div class="yk-flash err">' + esc(d.msg) + '</div>'; return; }
      if (!d.has_new) {
        box.innerHTML = '<div class="yk-flash ok">当前已是最新版本（远端版本 ' + esc(d.version) + '）</div>';
        return;
      }
      var html = '<table class="yk-table">'
        + '<tr><th width="120">新版本</th><td><b style="color:#ff7d2a">' + esc(d.version) + '</b></td></tr>'
        + '<tr><th>更新日志</th><td>' + esc(d.changelog || '（无）').replace(/\n/g, '<br>') + '</td></tr>'
        + '<tr><th>变动文件</th><td>' + d.files.length + ' 个</td></tr>'
        + '<tr><th>SQL 语句</th><td>' + d.sql_count + ' 条</td></tr></table>';
      if (d.files.length) {
        html += '<table class="yk-table" style="margin-top:10px"><tr><th>文件</th><th width="120">与本地对比</th></tr>';
        d.files.slice(0, 100).forEach(function(f){
          html += '<tr><td style="word-break:break-all">' + esc(f.path) + '</td><td>' + esc(f.state) + '</td></tr>';
        });
        if (d.files.length > 100) html += '<tr><td colspan="2" style="color:#999">…… 其余 ' + (d.files.length - 100) + ' 个文件从略</td></tr>';
        html += '</table>';
      }
      html += '<p style="margin-top:14px"><button class="yk-btn" type="button" id="btnUp" style="background:#ff7d2a">立即升级到 ' + esc(d.version) + '</button>'
        + '<span style="color:#999;font-size:12px;margin-left:10px">升级全程后台异步执行，自动备份数据库与全站文件</span></p>';
      box.innerHTML = html;
      document.getElementById('btnUp').addEventListener('click', function(){
        if (!confirm('升级前将自动备份数据库与全站文件，确定立即升级？')) return;
        this.disabled = true; this.textContent = '正在启动…';
        post('start', function(sd){
          if (!sd.ok) {
            alert(sd.msg || '启动失败');
            var b = document.getElementById('btnUp');
            if (b) { b.disabled = false; b.textContent = '立即升级'; }
            return;
          }
          document.getElementById('taskCard').style.display = '';
          poll(sd.task_id);
        });
      });
    });
  });
})();
</script>
<?php require dirname(__DIR__) . '/inc/footer.php'; ?>
