const socket = io();
const session_id = 'sess_' + Math.random().toString(36).slice(2,10);
socket.emit('join', { session_id });

const $ = (q)=>document.querySelector(q);
const timelineEl = $('#timeline');
const logOutputEl = $('#logOutput');

const stages = new Map(); // id -> element

function mkStage(id, title){
  if(stages.has(id)) return stages.get(id);
  const el = document.createElement('div');
  el.className = 'stage';
  el.innerHTML = `
    <div class="stage-header">
      <div class="stage-title">${title}</div>
      <div class="stage-status" data-status>Running…</div>
    </div>
    <div class="progress"><span></span></div>
    <div class="sub-steps" data-sub></div>
  `;
  timelineEl.appendChild(el);
  stages.set(id, el);
  return el;
}

function setStageProgress(id, percent, state){
  const el = stages.get(id); if(!el) return;
  el.querySelector('.progress > span').style.width = `${Math.max(0,Math.min(100,percent))}%`;
  const status = el.querySelector('[data-status]');
  if(state==='done'){ status.textContent = 'Done'; el.classList.add('done'); el.classList.remove('failed'); }
  else if(state==='failed'){ status.textContent = 'Failed'; el.classList.add('failed'); }
  else{ status.textContent = `${Math.round(percent)}%`; }
}

// Log handling
function addLog(data, type = 'stdout') {
  const line = document.createElement('div');
  line.className = `log-line log-${type}`;
  line.textContent = data;
  logOutputEl.appendChild(line);
  logOutputEl.scrollTop = logOutputEl.scrollHeight;
}

socket.on('joined', d=>{
  $('#userCode').textContent = d.user_code || '----';
});

socket.on('timeline_reset', ()=>{
  timelineEl.innerHTML = '';
  stages.clear();
  $('#result').textContent = '—';
});

socket.on('log_clear', ()=>{
  logOutputEl.innerHTML = '';
});

socket.on('log', d=>{
  addLog(d.data, d.type);
});

socket.on('status', d=>{
  $('#statusBadge').textContent = d.status || 'Waiting';
  $('#activity').textContent = d.activity || 'Idle';
});

socket.on('progress', d=>{
  const el = mkStage(d.id, d.title || d.id);
  if(typeof d.percent === 'number') setStageProgress(d.id, d.percent, d.state);
  if(d.state === 'done') setStageProgress(d.id, 100, 'done');
  if(d.state === 'failed') setStageProgress(d.id, 100, 'failed');
});

socket.on('result', d=>{
  if(d.ok && d.proxy){
    $('#result').textContent = d.proxy;
    addLog(`✅ Final result: ${d.proxy}`, 'success');
  }else if(d.ok === false){
    $('#result').textContent = `Error: ${d.error || 'Unknown'}`;
    addLog(`❌ Build failed: ${d.error || 'Unknown'}`, 'error');
  }
});

// Privacy-safe public feed
socket.on('public_notice', d=> addNotice(d.note, d.time));
socket.on('public_list', d=> (d.notices||[]).forEach(n=> addNotice(n.note, n.time)));
function addNotice(text, time){
  const el = document.createElement('div');
  el.className = 'notice';
  el.textContent = text;
  $('#publicList').prepend(el);
}

// Form submit
$('#buildBtn').addEventListener('click', async ()=>{
  const payload = {
    session_id,
    vps_ip: $('#vps_ip').value.trim(),
    vps_user: $('#vps_user').value.trim(),
    vps_pass: $('#vps_pass').value,
    vps_port: $('#vps_port').value || 22,
    proxy_user: $('#proxy_user').value.trim(),
    proxy_pass: $('#proxy_pass').value,
    broadcast: $('#broadcast').checked
  };
  // start
  $('#result').textContent = '—';
  try{
    const r = await fetch('/api/build', {
      method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(payload)
    });
    const j = await r.json();
    if(!j.ok){
      $('#statusBadge').textContent = 'Failed';
      $('#activity').textContent = j.error || 'Request failed';
    }
  }catch(e){
    $('#statusBadge').textContent = 'Failed';
    $('#activity').textContent = e.message || 'Network error';
  }
});