<?php
if (session_status() !== PHP_SESSION_ACTIVE) { @session_start(); }
$root = realpath(__DIR__ . '/..');
$configFile = $root . '/includes/config.php';
$lockFile = __DIR__ . '/installed.lock';
function mj_install_h($v) { return htmlspecialchars($v, ENT_QUOTES, 'UTF-8'); }
function mj_install_base_path() {
    $script = str_replace('\\', '/', (string)((isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : '/install/index.php')));
    $basePath = preg_replace('#/install/index\.php$#', '', $script);
    return rtrim((string)$basePath, '/') ?: '';
}
function mj_detect_base_url() {
    $https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (($_SERVER['SERVER_PORT'] ?? '') == 443);
    $scheme = $https ? 'https' : 'http';
    $host = (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost');
    return $scheme . '://' . $host . mj_install_base_path();
}
function mj_installed_config($configFile) {
    if (!is_file($configFile)) { return null; }
    $cfg = require $configFile;
    return (is_array($cfg) && !empty($cfg['installed'])) ? $cfg : null;
}
$installedCfg = mj_installed_config($configFile);
if ($installedCfg && empty($_GET['force'])) {
    $basePath = mj_install_base_path();
    ?><!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>MJ Marketplace Already Installed</title><link rel="stylesheet" href="../assets/css/style.css"><style>.wrap{max-width:880px;margin:40px auto}.box{background:#fff;border-radius:16px;padding:28px;box-shadow:0 10px 30px rgba(15,23,42,.08)}</style></head><body><div class="wrap"><div class="box"><h1>MJ Marketplace is already installed</h1><p>The installer found <b>includes/config.php</b> and installation is locked.</p><p>For security, rename or delete the <b>/install</b> folder now.</p><a class="btn-primary" href="<?=mj_install_h($basePath)?>/admin/index.php">Go to Admin</a> <a class="btn-secondary" href="<?=mj_install_h($basePath)?>/index.php">View Website</a><hr><p class="text-muted">Need to reinstall? Delete <code>includes/config.php</code> and <code>install/installed.lock</code>, or open <code>?force=1</code> only for testing.</p></div></div></body></html><?php
    exit;
}
$detectedBase = mj_detect_base_url();
?><!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>MJ Marketplace v3.0.4.2.14 Advanced Installer</title>
<link rel="stylesheet" href="../assets/css/style.css">
<style>
:root{--mj:#2563eb;--ok:#16a34a;--bad:#dc2626;--warn:#d97706;--soft:#f8fafc;--line:#e5e7eb;--dark:#0f172a}
body{background:#f1f5f9;color:#0f172a}.installer{max-width:1180px;margin:24px auto;padding:0 14px}.hero{background:linear-gradient(135deg,#0f172a,#1d4ed8);color:#fff;border-radius:24px;padding:28px;box-shadow:0 14px 35px rgba(15,23,42,.18)}.hero h1{margin:0;font-size:30px}.hero p{opacity:.92}.grid{display:grid;grid-template-columns:360px 1fr;gap:18px;margin-top:18px}.card{background:#fff;border:1px solid var(--line);border-radius:18px;box-shadow:0 8px 28px rgba(15,23,42,.06);overflow:hidden}.card h2{margin:0 0 12px;font-size:20px}.card-body{padding:18px}.label{font-weight:700;margin:12px 0 6px;display:block}.form-control,.select-control{width:100%;box-sizing:border-box;border:1px solid #cbd5e1;border-radius:12px;padding:11px 12px;background:#fff}.hint{font-size:12px;color:#64748b}.row{display:grid;grid-template-columns:1fr 1fr;gap:10px}.checkrow{display:flex;align-items:flex-start;gap:10px;margin:12px 0}.checkrow input{margin-top:4px}.btn{border:0;border-radius:12px;padding:11px 15px;font-weight:800;cursor:pointer}.btn-primary{background:var(--mj);color:#fff}.btn-secondary{background:#e2e8f0;color:#0f172a}.btn-danger{background:#dc2626;color:#fff}.btn:disabled{opacity:.55;cursor:not-allowed}.progress{height:18px;background:#e2e8f0;border-radius:999px;overflow:hidden}.bar{height:100%;width:0;background:linear-gradient(90deg,#2563eb,#22c55e);transition:.2s}.status-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px}.stat{background:var(--soft);border:1px solid var(--line);border-radius:14px;padding:12px}.stat b{display:block;font-size:20px}.log{height:290px;overflow:auto;background:#020617;color:#d1fae5;border-radius:14px;padding:12px;font-family:Consolas,monospace;font-size:12px;line-height:1.5}.pill{display:inline-block;border-radius:999px;padding:4px 10px;font-size:12px;font-weight:800}.pill-ok{background:#dcfce7;color:#166534}.pill-bad{background:#fee2e2;color:#991b1b}.pill-warn{background:#fef3c7;color:#92400e}.req-list{max-height:260px;overflow:auto}.req{display:flex;justify-content:space-between;gap:10px;border-bottom:1px solid #eef2f7;padding:8px 0}.alert{border-radius:14px;padding:12px 14px;margin:12px 0}.alert-danger{background:#fef2f2;border:1px solid #fecaca;color:#991b1b}.alert-ok{background:#ecfdf5;border:1px solid #bbf7d0;color:#166534}.alert-warn{background:#fffbeb;border:1px solid #fde68a;color:#92400e}.hidden{display:none!important}.actions{display:flex;gap:10px;flex-wrap:wrap}.small{font-size:12px}.final-table{width:100%;border-collapse:collapse}.final-table th,.final-table td{border-bottom:1px solid #e5e7eb;padding:8px;text-align:left}@media(max-width:900px){.grid{grid-template-columns:1fr}.status-grid{grid-template-columns:1fr 1fr}.row{grid-template-columns:1fr}}
</style>
</head>
<body>
<div class="installer">
  <div class="hero">
    <h1>MJ Marketplace v3.0.4.2.14 Advanced Installer</h1>
    <p>Batch-based fresh installer. Shows current table processing, avoids browser hang/504 timeout, supports resume, repair, reset, sample data, logs and final checks. No v3.0.5 city importer included.</p>
  </div>

  <div class="grid">
    <div class="card">
      <div class="card-body">
        <h2>Install Settings</h2>
        <label class="label">Install mode</label>
        <select id="mode" class="select-control">
          <option value="fresh">Fresh install, empty database</option>
          <option value="repair">Repair existing install / continue safely</option>
          <option value="reset">Reset database and reinstall</option>
        </select>
        <div class="alert alert-warn small">Reset mode drops existing tables/views in the selected database. Use only on a fresh/demo website.</div>

        <label class="label">DB Host</label><input class="form-control" id="db_host" value="localhost">
        <label class="label">DB Name</label><input class="form-control" id="db_name" value="mj_marketplace">
        <label class="label">DB User</label><input class="form-control" id="db_user" value="root">
        <label class="label">DB Password</label><input class="form-control" id="db_pass" type="password">
        <label class="label">Base URL</label><input class="form-control" id="base_url" value="<?=mj_install_h($detectedBase)?>">

        <h2 style="margin-top:18px">Admin Account</h2>
        <label class="label">Admin Name</label><input class="form-control" id="admin_name" value="Admin">
        <label class="label">Admin Email</label><input class="form-control" id="admin_email" type="email">
        <label class="label">Admin Password</label><input class="form-control" id="admin_pass" type="password">

        <h2 style="margin-top:18px">Options</h2>
        <div class="checkrow"><input type="checkbox" id="sample_data"><label for="sample_data"><b>Install sample users/listings/companies/deals/leads</b><br><span class="hint">Optional demo data only.</span></label></div>
        <div class="checkrow"><input type="checkbox" id="safe_continue" checked><label for="safe_continue"><b>Safe continue for duplicate schema warnings</b><br><span class="hint">Helps repair mode continue if a column/table already exists.</span></label></div>
        <label class="label">Batch size</label>
        <select id="batch_size" class="select-control">
          <option value="5">Very slow safest: 5 statements/request</option>
          <option value="10" selected>Recommended safe: 10 statements/request</option>
          <option value="25">Normal: 25 statements/request</option>
          <option value="50">Fast: 50 statements/request</option>
        </select>
        <br><br>
        <div class="actions">
          <button id="btnStart" class="btn btn-primary">Start Install</button>
          <button id="btnPause" class="btn btn-secondary" disabled>Pause</button>
          <button id="btnResume" class="btn btn-secondary">Resume</button>
          <button id="btnClear" class="btn btn-danger">Clear Progress</button>
        </div>
      </div>
    </div>

    <div>
      <div class="card"><div class="card-body">
        <h2>Server Checks</h2>
        <div id="requirements" class="req-list"><span class="hint">Loading checks...</span></div>
      </div></div>

      <div class="card" style="margin-top:18px"><div class="card-body">
        <h2>Install Progress</h2>
        <div class="status-grid">
          <div class="stat"><span class="hint">Phase</span><b id="phase">Idle</b></div>
          <div class="stat"><span class="hint">Current table</span><b id="table">-</b></div>
          <div class="stat"><span class="hint">Statements</span><b id="statements">0 / 0</b></div>
          <div class="stat"><span class="hint">Skipped</span><b id="skipped">0</b></div>
        </div>
        <div style="margin:14px 0 8px"><div class="progress"><div class="bar" id="bar"></div></div></div>
        <div class="small"><b>Last SQL:</b> <span id="lastSql" class="hint">-</span></div>
        <div id="message"></div>
        <div id="finalChecks" class="hidden"></div>
      </div></div>

      <div class="card" style="margin-top:18px"><div class="card-body">
        <h2>Live Install Log</h2>
        <div class="actions" style="margin-bottom:10px"><button id="btnDownload" class="btn btn-secondary">Download Log</button><button id="btnRefresh" class="btn btn-secondary">Refresh Status</button></div>
        <div id="log" class="log"></div>
      </div></div>
    </div>
  </div>
</div>
<script>
let running = false;
let paused = false;
let busy = false;
let installId = localStorage.getItem('mj_install_id') || '';
function addInstallId(fd){ if(installId){ fd.append('install_id', installId); } return fd; }
const $ = (id)=>document.getElementById(id);
function esc(s){return String(s??'').replace(/[&<>'"]/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;',"'":'&#039;','"':'&quot;'}[c]));}
function formData(action){
  const fd = new FormData(); fd.append('action', action); addInstallId(fd);
  ['mode','db_host','db_name','db_user','db_pass','base_url','admin_name','admin_email','admin_pass','batch_size'].forEach(id=>fd.append(id, $(id).value));
  if($('sample_data').checked) fd.append('sample_data','1');
  if($('safe_continue').checked) fd.append('safe_continue','1');
  return fd;
}
async function api(action, data=null){
  const fd = data || formData(action); if(!data) fd.set('action', action); addInstallId(fd);
  const res = await fetch('install-runner.php', {method:'POST', body:fd, credentials:'same-origin'});
  const text = await res.text();
  try { return JSON.parse(text); }
  catch(e){
    return {ok:false, error:'Installer runner returned non-JSON response. HTTP '+res.status+' '+res.statusText+'. This is usually PHP version/permission/server error. Preview: '+text.slice(0,700)};
  }
}
function renderLog(lines){ $('log').innerHTML = (lines||[]).map(esc).join('<br>'); $('log').scrollTop = $('log').scrollHeight; }
function showMsg(type,msg){ $('message').innerHTML = msg ? `<div class="alert alert-${type}">${esc(msg)}</div>` : ''; }
function updateState(state, log){
  state = state || {};
  const phase = state.phase || 'Idle';
  $('phase').textContent = phase;
  $('table').textContent = state.current_table || '-';
  let total = phase === 'sample' ? (state.sample_total||0) : (state.core_total||0);
  let index = phase === 'sample' ? (state.sample_statement_index||0) : (state.statement_index||0);
  if(phase === 'done' || state.done){ index = total || index; }
  $('statements').textContent = index + ' / ' + total;
  $('skipped').textContent = state.skipped_statements || 0;
  $('lastSql').textContent = state.last_sql_preview || '-';
  let pct = total ? Math.min(100, Math.round((index/total)*100)) : 0;
  if(phase === 'done' || state.done) pct = 100;
  $('bar').style.width = pct+'%';
  renderLog(log);
  if(state.done){ renderFinal(state.final_checks || []); }
}
function renderFinal(checks){
  if(!checks.length) return;
  $('finalChecks').classList.remove('hidden');
  $('finalChecks').innerHTML = '<h3>Final Table Checks</h3><table class="final-table"><thead><tr><th>Table</th><th>Status</th><th>Rows</th></tr></thead><tbody>'+checks.map(r=>`<tr><td>${esc(r.table)}</td><td>${r.ok?'<span class="pill pill-ok">OK</span>':'<span class="pill pill-bad">Missing/Error</span>'}</td><td>${esc(r.count ?? r.error ?? '')}</td></tr>`).join('')+'</tbody></table><div class="alert alert-ok"><b>Installation complete.</b> Delete or rename the /install folder now. <a href="../admin/index.php">Go to Admin</a></div>';
}
async function loadRequirements(){
  const r = await api('requirements', new FormData(Object.assign(document.createElement('form'), {})));
}
async function req(){
  const fd = new FormData(); fd.append('action','requirements');
  const r = await api('requirements', fd);
  if(!r.ok){ $('requirements').innerHTML = '<div class="alert alert-danger">'+esc(r.error)+'</div>'; return; }
  $('requirements').innerHTML = r.checks.map(c=>`<div class="req"><span>${esc(c.name)}<br><small class="hint">${esc(c.value)}</small></span><span class="pill ${c.ok?'pill-ok':'pill-bad'}">${c.ok?'OK':'Check'}</span></div>`).join('');
  renderLog(r.log||[]);
}
async function startInstall(){
  if(!confirm('Start installation now? Backup first if this is not an empty database.')) return;
  running=true; paused=false; busy=true; $('btnStart').disabled=true; $('btnPause').disabled=false; showMsg('warn','Starting installer...');
  const r = await api('start'); busy=false;
  if(!r.ok){ running=false; $('btnStart').disabled=false; $('btnPause').disabled=true; showMsg('danger', r.error); updateState(r.state,r.log); return; }
  installId = r.install_id || (r.state && r.state.install_id) || installId; if(installId){ localStorage.setItem('mj_install_id', installId); } showMsg('ok','Install started. Running safe batches...'); updateState(r.state,r.log); loop();
}
async function loop(){
  if(!running || paused || busy) return;
  busy=true;
  const st = await api('status', (()=>{let f=new FormData();f.append('action','status');return f;})());
  if(st.ok && st.state && st.state.phase === 'finalize'){
    const fin = await api('finalize', (()=>{let f=new FormData();f.append('action','finalize');return f;})()); busy=false;
    updateState(fin.state, fin.log);
    if(fin.ok){ running=false; $('btnPause').disabled=true; $('btnStart').disabled=false; showMsg('ok','Installation complete. Delete or rename /install folder.'); } else { running=false; showMsg('danger', fin.error); }
    return;
  }
  const r = await api('batch', (()=>{let f=new FormData();f.append('action','batch');return f;})()); busy=false;
  updateState(r.state, r.log);
  if(!r.ok){ running=false; $('btnStart').disabled=false; $('btnPause').disabled=true; showMsg('danger', r.error); return; }
  if(r.state && r.state.phase === 'finalize'){ setTimeout(loop, 150); return; }
  if(r.state && r.state.done){ running=false; $('btnPause').disabled=true; $('btnStart').disabled=false; showMsg('ok','Installation complete.'); return; }
  setTimeout(loop, 120);
}
async function resume(){ installId = localStorage.getItem('mj_install_id') || installId; if(!installId){ showMsg('danger','No saved install session found. Click Start Install first.'); return; } running=true; paused=false; $('btnPause').disabled=false; $('btnStart').disabled=true; showMsg('warn','Resuming from saved checkpoint...'); loop(); }
async function refresh(){ const r = await api('status', (()=>{let f=new FormData();f.append('action','status');return f;})()); if(r.ok) updateState(r.state,r.log); }
$('btnStart').onclick = startInstall;
$('btnPause').onclick = ()=>{ paused=true; running=false; $('btnStart').disabled=false; $('btnPause').disabled=true; showMsg('warn','Paused. Click Resume to continue from checkpoint.'); };
$('btnResume').onclick = resume;
$('btnRefresh').onclick = refresh;
$('btnClear').onclick = async()=>{ if(!confirm('Clear installer progress/log? This does not delete database tables.')) return; const f=new FormData(); f.append('action','reset_state'); const r=await api('reset_state',f); if(r.ok){ localStorage.removeItem('mj_install_id'); installId=''; } showMsg(r.ok?'ok':'danger', r.ok?'Progress cleared.':r.error); await refresh(); };
$('btnDownload').onclick = ()=>{ window.location='install-runner.php?action=download_log' + (installId ? '&install_id=' + encodeURIComponent(installId) : ''); };
req(); refresh();
</script>
</body></html>
