/* ─────────────────────────────────────────────────────────────
   Setup 탭 — Multi-Controller Gateway 상태 / 설정 / 로그
   ───────────────────────────────────────────────────────────── */

let _setupInterval = null;

async function _setupApi(method, path, body) {
  const opts = { method, headers: { 'Content-Type': 'application/json' } };
  if (body !== undefined) opts.body = JSON.stringify(body);
  const r = await fetch('/api/setup' + path, opts);
  return r.json();
}

function _setupMsg(id, ok, text) {
  const el = document.getElementById(id);
  if (!el) return;
  el.className = 'setup-msg ' + (ok ? 'ok' : 'err');
  el.textContent = text;
  setTimeout(() => el.className = 'setup-msg', 4000);
}

function _setText(id, val) {
  const el = document.getElementById(id);
  if (el) el.textContent = val;
}

function _val(c, pascal, camel, def) {
  return (c[pascal] ?? c[camel] ?? def);
}
function _norm(cfg) {
  cfg.Shared      = cfg.Shared ?? cfg.shared ?? {};
  cfg.shared      = cfg.Shared;
  cfg.Controllers = cfg.Controllers ?? cfg.controllers ?? [];
  cfg.controllers = cfg.Controllers;
  return cfg;
}
function _ctrlCardHTML(c) {
  const cid = _val(c, 'Id', 'id', '?');
  const ip = _val(c, 'ControllerIp', 'controllerIp', '');
  const mb = _val(c, 'ControllerPort', 'controllerPort', 502);
  const gr = _val(c, 'GrpcPort', 'grpcPort', 50051);
  const po = _val(c, 'PollIntervalMs', 'pollIntervalMs', 1000);
  const rm = _val(c, 'RegisterMapPath', 'registerMapPath', '');
  const en = _val(c, 'Enabled', 'enabled', true);
  return `<div class="setup-ctrl-card" id="ctrl-card-${cid}">
    <div class="setup-ctrl-hdr">
      <div class="setup-dot" id="dot-${cid}"></div>
      <h4>${cid}: <span id="hdr-ip-${cid}">${_val(c, 'ControllerIp', 'controllerIp', '?')}</span>
        <strong id="hdr-conn-${cid}" style="color:#666">❌</strong>
        <span id="hdr-run-${cid}" style="color:#888;font-size:12px">STOP</span>
      </h4>
    </div>
    <div class="setup-field">
      <label>IP</label>
      <input id="ip-${cid}" type="text" value="${ip}">
    </div>
    <div class="setup-field">
      <label>Modbus Port</label>
      <input id="mbport-${cid}" type="number" value="${mb}" class="slim">
      <label style="width:auto">gRPC Port</label>
      <input id="grpc-${cid}" type="number" value="${gr}" class="slim">
      <label style="width:auto">Poll (ms)</label>
      <input id="poll-${cid}" type="number" value="${po}" class="slim">
    </div>
    <div class="setup-field">
      <label>Register Map</label>
      <input id="regmap-${cid}" type="text" value="${rm}">
    </div>
    <div class="setup-field">
      <label>Enabled</label>
      <input id="enabled-${cid}" type="checkbox" ${en ? 'checked' : ''} style="width:auto">
    </div>
    <div class="setup-ir setup-mt8">
      <div class="setup-ii"><span>PID: </span><strong id="pid-${cid}">—</strong></div>
      <div class="setup-ii"><span>Started: </span><strong id="started-${cid}">—</strong></div>
      <div class="setup-ii"><span>Crawler: </span><strong id="cr-conn-${cid}">—</strong></div>
    </div>
    <div class="setup-btn-row">
      <button class="setup-btn success sm" onclick="startCtrl('${cid}')">▶ Start</button>
      <button class="setup-btn danger sm"  onclick="stopCtrl('${cid}')">■ Stop</button>
      <button class="setup-btn warning sm" onclick="restartCtrl('${cid}')">↺ Restart</button>
      <button class="setup-btn primary sm" onclick="saveCtrl('${cid}')">💾 Save</button>
      <button class="setup-btn danger sm"  onclick="deleteCtrl('${cid}')" style="margin-left:auto">✕ Delete</button>
    </div>
    <div id="msg-${cid}" class="setup-msg"></div>
  </div>`;
}

async function loadAll() {
  try {
    const cfg = _norm(await _setupApi('GET', '/config'));

    document.getElementById('cfg-bin').value    = cfg.shared.binaryPath ?? '';
    document.getElementById('cfg-ld').value     = cfg.shared.ldLibraryPath ?? '';
    document.getElementById('cfg-logdir').value = cfg.shared.logDir ?? '/tmp';

    const grid = document.getElementById('ctrl-grid');
    if (grid) {
      grid.innerHTML = cfg.controllers.map(_ctrlCardHTML).join('');
    }

    const sel = document.getElementById('log-ctrl-select');
    if (sel) {
      sel.innerHTML = cfg.controllers.map(c => {
        const cid = _val(c, 'Id', 'id', '?');
        const nm = _val(c, 'Name', 'name', '');
        return `<option value="${cid}">${cid} — ${nm || cid}</option>`;
      }).join('');
    }

    refreshAll();
  } catch(e) { console.error('loadAll:', e); }
}

async function refreshAll() {
  try {
    const s = await _setupApi('GET', '/gateway/status');
    _setText('crawler-poll',     (s.crawlerPollCount ?? 0).toLocaleString());
    _setText('crawler-lastpoll', s.crawlerLastPoll ? new Date(s.crawlerLastPoll).toLocaleTimeString('ko-KR') : '—');
    _setText('crawler-connected', s.crawlerConnected ? '✅' : '❌');

    // Per-controller connection list (global card) + card updates
    const connList = document.getElementById('ctrl-conn-list');
    if (connList && s.controllers) {
      connList.innerHTML = s.controllers.map(cs => {
        const id = cs.ControllerId ?? cs.controllerId;
        const ip = cs.ControllerIp ?? cs.controllerIp ?? '';
        return `<div class="setup-ii" style="white-space:nowrap">
          <span>${id}</span>
          ${ip ? `<span style="color:#888;font-size:11px"> ${ip}</span>` : ''}
          <strong style="color:${cs.crawlerConnected ? '#3c3' : '#c33'}">${cs.crawlerConnected ? '✅' : '❌'}</strong>
          <span style="color:#666;font-size:11px"> ${(cs.Running ?? cs.running) ? 'RUN' : 'STOP'}</span>
        </div>`;
      }).join('');

      for (const cs of s.controllers) {
        const id = cs.ControllerId ?? cs.controllerId;
        const dot = document.getElementById('dot-' + id);
        const running = cs.Running ?? cs.running ?? false;
        const crawlerOk = cs.crawlerConnected ?? false;
        const pid = cs.Pid ?? cs.pid;
        const ip = cs.ControllerIp ?? cs.controllerIp ?? '';

        if (dot) {
          if (running && crawlerOk) dot.className = 'setup-dot green';
          else if (running) dot.className = 'setup-dot yellow';
          else dot.className = 'setup-dot red';
        }
        _setText('hdr-ip-' + id, ip || '?');
        const hdrConn = document.getElementById('hdr-conn-' + id);
        if (hdrConn) { hdrConn.textContent = crawlerOk ? '✅' : '❌'; hdrConn.style.color = crawlerOk ? '#3c3' : '#c33'; }
        _setText('hdr-run-' + id, running ? 'RUN' : 'STOP');
        _setText('pid-' + id, pid ?? '—');
        _setText('started-' + id, (cs.StartedAt ?? cs.startedAt)
          ? new Date(cs.StartedAt ?? cs.startedAt).toLocaleTimeString('ko-KR') : '—');
        _setText('cr-conn-' + id, crawlerOk ? '✅' : '❌');
      }
    }
  } catch(e) { console.error('refreshAll:', e); }
}

async function startCtrl(id) {
  const r = await _setupApi('POST', '/gateway/start?id=' + encodeURIComponent(id));
  _setupMsg('msg-' + id, r.success ?? r.ok, r.message ?? (r.ok ? '시작됨' : '실패'));
  setTimeout(refreshAll, 2500);
}

async function stopCtrl(id) {
  const r = await _setupApi('POST', '/gateway/stop?id=' + encodeURIComponent(id));
  _setupMsg('msg-' + id, r.success ?? r.ok, r.message ?? (r.ok ? '중지됨' : '실패'));
  setTimeout(refreshAll, 1000);
}

async function restartCtrl(id) {
  const r = await _setupApi('POST', '/gateway/restart?id=' + encodeURIComponent(id));
  _setupMsg('msg-' + id, r.success ?? r.ok, r.message ?? (r.ok ? '재시작됨' : '실패'));
  setTimeout(refreshAll, 3000);
}

async function saveCtrl(id) {
  const cfg = _norm(await _setupApi('GET', '/config'));
  const ctrl = cfg.controllers.find(c => (c.Id ?? c.id) === id);
  if (!ctrl) return;
  const ipEl = document.getElementById('ip-' + id);
  if (ipEl && ipEl.value.trim()) ctrl.controllerIp = ipEl.value.trim();
  const mbEl = document.getElementById('mbport-' + id);
  if (mbEl) ctrl.controllerPort = parseInt(mbEl.value) || 502;
  const grEl = document.getElementById('grpc-' + id);
  if (grEl) ctrl.grpcPort = parseInt(grEl.value) || 50051;
  const poEl = document.getElementById('poll-' + id);
  if (poEl) ctrl.pollIntervalMs = parseInt(poEl.value) || 1000;
  const rmEl = document.getElementById('regmap-' + id);
  if (rmEl && rmEl.value.trim()) ctrl.registerMapPath = rmEl.value.trim();
  const enEl = document.getElementById('enabled-' + id);
  if (enEl) ctrl.enabled = enEl.checked;
  const r = await _setupApi('POST', '/config', cfg);
  _setupMsg('msg-' + id, r.success, r.message);
}

async function deleteCtrl(id) {
  if (!confirm(`Delete controller ${id}?`)) return;
  const cfg = _norm(await _setupApi('GET', '/config'));
  const before = cfg.controllers.length;
  cfg.controllers = cfg.controllers.filter(c => (c.Id ?? c.id) !== id);
  if (cfg.controllers.length === before) return;
  const r = await _setupApi('POST', '/config', cfg);
  _setupMsg('add-msg', r.success, r.message);
  if (r.success) loadAll();
}

async function saveSharedConfig() {
  const cfg = _norm(await _setupApi('GET', '/config'));
  cfg.shared.binaryPath    = document.getElementById('cfg-bin').value.trim();
  cfg.shared.ldLibraryPath = document.getElementById('cfg-ld').value.trim();
  cfg.shared.logDir        = document.getElementById('cfg-logdir').value.trim();
  const r = await _setupApi('POST', '/config', cfg);
  _setupMsg('shared-msg', r.success, r.message);
}

async function addController() {
  const cfg = _norm(await _setupApi('GET', '/config'));
  cfg.controllers.push({
    id:              document.getElementById('new-id').value.trim() || 'HCX',
    name:            document.getElementById('new-name').value.trim(),
    controllerIp:    document.getElementById('new-ip').value.trim(),
    controllerPort:  parseInt(document.getElementById('new-port').value) || 502,
    grpcPort:        parseInt(document.getElementById('new-grpc').value) || 50051,
    pollIntervalMs:  parseInt(document.getElementById('new-poll').value) || 1000,
    registerMapPath: document.getElementById('new-regmap').value.trim(),
    enabled:         true,
  });
  const r = await _setupApi('POST', '/config', cfg);
  _setupMsg('add-msg', r.success, r.message);
  if (r.success) {
    loadAll();
    document.getElementById('new-id').value = '';
    document.getElementById('new-name').value = '';
    document.getElementById('new-ip').value = '';
    document.getElementById('new-regmap').value = '';
  }
}


async function refreshLog() {
  const sel = document.getElementById('log-ctrl-select');
  const id = (sel && sel.value) || '';
  const d = await _setupApi('GET', '/gateway/log?id=' + encodeURIComponent(id) + '&lines=80');
  const lb = document.getElementById('log-box');
  if (lb) {
    lb.textContent = (d.log || []).join('\n') || '로그 없음';
    lb.scrollTop = 9999;
  }
}

async function startAll() {
  const r = await _setupApi('POST', '/gateway/start');
  _setupMsg('global-msg', true, Array.isArray(r) ? r.map(x => `${x.Id ?? x.id}:${(x.ok ?? x.success) ? 'OK' : 'FAIL'}`).join(', ') : (r.success ? '전체 시작됨' : '실패'));
  setTimeout(refreshAll, 2500);
}

async function stopAll() {
  const r = await _setupApi('POST', '/gateway/stop');
  _setupMsg('global-msg', true, Array.isArray(r) ? r.map(x => `${x.Id ?? x.id}:${(x.ok ?? x.success) ? 'OK' : 'FAIL'}`).join(', ') : (r.success ? '전체 중지됨' : '실패'));
  setTimeout(refreshAll, 1000);
}

async function restartAll() {
  const r = await _setupApi('POST', '/gateway/restart');
  _setupMsg('global-msg', true, Array.isArray(r) ? r.map(x => `${x.Id ?? x.id}:${(x.ok ?? x.success) ? 'OK' : 'FAIL'}`).join(', ') : (r.success ? '전체 재시작됨' : '실패'));
  setTimeout(refreshAll, 3000);
}

paneInit.setup = function () {
  loadAll();
  if (!_setupInterval) {
    _setupInterval = setInterval(refreshAll, 5000);
  }
};
