{% extends "base.html" %}
{% block title %}{{ t(request, 'page.explorer') }} — MoE Admin{% endblock %}

{% block content %}
<div class="d-flex align-items-center justify-content-between mb-3">
  <h5 class="mb-0 fw-bold">
    <i class="bi bi-bezier2 me-2 text-primary"></i>{{ t(request, 'page.explorer') }}
  </h5>
  <a href="http://{{ request.headers.get('host', '').split(':')[0] }}:7474"
     target="_blank" class="btn btn-sm btn-outline-secondary">
    <i class="bi bi-box-arrow-up-right me-1"></i>{{ t(request, 'lbl.open_neo4j_browser') }}
  </a>
</div>

<div class="alert alert-info small">
  <i class="bi bi-shield-check me-2"></i>{{ t(request, 'lbl.explorer_readonly_notice') }}
</div>

<div class="card mb-3">
  <div class="card-body">
    <label class="form-label small text-muted mb-1">{{ t(request, 'lbl.cypher_query') }}</label>
    <textarea id="cypher-query" class="form-control font-monospace" rows="6"
              spellcheck="false">MATCH (e:Entity) RETURN e.name AS name, e.domain AS domain, e.trust AS trust ORDER BY e.trust DESC LIMIT 25</textarea>
    <div class="d-flex justify-content-between mt-2">
      <div>
        <select id="cypher-preset" class="form-select form-select-sm d-inline-block w-auto"
                onchange="loadPreset()">
          <option value="">{{ t(request, 'lbl.preset_select') }}</option>
          <option value="entities_top">{{ t(request, 'lbl.preset_top_entities') }}</option>
          <option value="domains">{{ t(request, 'lbl.preset_domains') }}</option>
          <option value="schema">{{ t(request, 'lbl.preset_schema') }}</option>
          <option value="recent">{{ t(request, 'lbl.preset_recent') }}</option>
        </select>
        <span class="text-muted small ms-2" id="cypher-meta">–</span>
      </div>
      <button class="btn btn-sm btn-primary" onclick="runQuery()">
        <i class="bi bi-play-fill me-1"></i>{{ t(request, 'btn.run_query') }}
      </button>
    </div>
  </div>
</div>

<div class="card">
  <div class="card-body p-0">
    <div class="table-responsive" style="max-height:60vh;overflow:auto">
      <table class="table table-sm table-hover mb-0" id="cypher-result-table">
        <thead class="table-light"><tr><th class="text-muted small">{{ t(request, 'lbl.no_query_run') }}</th></tr></thead>
        <tbody></tbody>
      </table>
    </div>
  </div>
</div>

<script>
const PRESETS = {
  entities_top: "MATCH (e:Entity) RETURN e.name AS name, e.domain AS domain, e.trust AS trust ORDER BY e.trust DESC LIMIT 25",
  domains:      "MATCH (e:Entity) WITH coalesce(e.domain, 'unknown') AS domain, count(e) AS count RETURN domain, count ORDER BY count DESC",
  schema:       "CALL db.schema.visualization()",
  recent:       "MATCH (e:Entity) WHERE e.created_at IS NOT NULL RETURN e.name AS name, e.domain AS domain, e.created_at AS created ORDER BY e.created_at DESC LIMIT 25",
};

function loadPreset() {
  const v = document.getElementById("cypher-preset").value;
  if (PRESETS[v]) document.getElementById("cypher-query").value = PRESETS[v];
}

function escapeCell(v) {
  if (v == null) return "";
  if (typeof v === "object") return JSON.stringify(v);
  return String(v);
}

async function runQuery() {
  const q = document.getElementById("cypher-query").value;
  const meta = document.getElementById("cypher-meta");
  meta.textContent = "{{ t(request, 'lbl.running') }}…";
  try {
    const r = await fetch("/api/explorer/cypher", {
      method: "POST",
      headers: {"Content-Type": "application/json"},
      body: JSON.stringify({query: q, limit: 250}),
    });
    const data = await r.json();
    const tbl = document.getElementById("cypher-result-table");
    if (data.error) {
      tbl.innerHTML = `<thead class="table-light"><tr><th class="text-danger">{{ t(request, 'lbl.error') }}</th></tr></thead><tbody><tr><td><pre class="mb-0 small">${data.error.replace(/[<>]/g, "")}</pre></td></tr></tbody>`;
      meta.textContent = "error";
      return;
    }
    const cols = data.columns || [];
    const rows = data.rows || [];
    if (!rows.length) {
      tbl.innerHTML = `<thead class="table-light"><tr><th class="text-muted">{{ t(request, 'lbl.no_data') }}</th></tr></thead><tbody></tbody>`;
      meta.textContent = "0 " + "{{ t(request, 'lbl.rows') }}";
      return;
    }
    const header = cols.map(c => `<th class="small">${escapeCell(c).replace(/[<>]/g, "")}</th>`).join("");
    const body = rows.map(row => {
      return "<tr>" + cols.map(c => `<td class="small font-monospace">${escapeCell(row[c]).replace(/[<>]/g, "")}</td>`).join("") + "</tr>";
    }).join("");
    tbl.innerHTML = `<thead class="table-light"><tr>${header}</tr></thead><tbody>${body}</tbody>`;
    meta.textContent = `${rows.length} ${rows.length === 1 ? "{{ t(request, 'lbl.row') }}" : "{{ t(request, 'lbl.rows') }}"}` +
                      (rows.length >= (data.limit || 100) ? ` ({{ t(request, 'lbl.limit_reached') }})` : "");
  } catch (e) {
    meta.textContent = "error";
    console.error(e);
  }
}
</script>
{% endblock %}
