<?php
require_once __DIR__ . '/../../app/core/bootstrap.php';
auth_require_login();
$user = auth_user();
if (($user['role'] ?? '') !== 'admin') {
    header('Location: /gopools/public/dashboard/'); exit;
}
$csrf = csrf_token();
?><!DOCTYPE html>
<html lang="el">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Editor · GoPools CRM</title>

<!-- CodeMirror 5 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/codemirror.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/theme/dracula.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/mode/php/php.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/mode/javascript/javascript.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/mode/css/css.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/mode/xml/xml.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/mode/htmlmixed/htmlmixed.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/mode/sql/sql.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/mode/markdown/markdown.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/mode/yaml/yaml.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/addon/edit/matchbrackets.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/addon/edit/closebrackets.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/addon/search/search.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/addon/search/searchcursor.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/addon/dialog/dialog.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/addon/dialog/dialog.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/addon/fold/foldcode.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/addon/fold/brace-fold.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/addon/fold/foldgutter.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.17/addon/fold/foldgutter.min.css">

<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  --bg:       #0d1117;
  --surface:  #161b22;
  --surface2: #1c2128;
  --border:   #30363d;
  --primary:  #2563eb;
  --accent:   #58a6ff;
  --green:    #3fb950;
  --red:      #f85149;
  --yellow:   #d29922;
  --text:     #e6edf3;
  --muted:    #8b949e;
  --sidebar-w: 280px;
  --topbar-h:  48px;
}

html, body { height: 100%; overflow: hidden; font-family: 'Segoe UI', system-ui, sans-serif; background: var(--bg); color: var(--text); font-size: 13px; }

/* ── Top Bar ── */
#topbar {
  position: fixed; top: 0; left: 0; right: 0; height: var(--topbar-h);
  background: var(--surface); border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 8px; padding: 0 12px; z-index: 100;
}
#topbar .logo { font-weight: 800; font-size: 14px; color: var(--accent); margin-right: 8px; white-space: nowrap; }
#current-file {
  flex: 1; font-size: 12px; color: var(--muted); white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; font-family: 'Consolas', monospace; padding: 4px 8px;
  background: var(--surface2); border-radius: 6px; border: 1px solid var(--border);
}
#file-meta { font-size: 11px; color: var(--muted); white-space: nowrap; }
#btn-save {
  padding: 6px 18px; background: var(--green); color: #000; border: none;
  border-radius: 6px; font-weight: 700; font-size: 12px; cursor: pointer;
  transition: opacity .15s; white-space: nowrap;
}
#btn-save:hover { opacity: .85; }
#btn-save:disabled { opacity: .4; cursor: default; }
#save-status { font-size: 11px; color: var(--green); white-space: nowrap; min-width: 80px; text-align: right; }
.btn-top {
  padding: 5px 10px; background: var(--surface2); color: var(--text); border: 1px solid var(--border);
  border-radius: 6px; font-size: 11px; cursor: pointer; transition: border-color .15s;
  white-space: nowrap;
}
.btn-top:hover { border-color: var(--accent); color: var(--accent); }

/* ── Layout ── */
#layout {
  display: flex; height: 100vh; padding-top: var(--topbar-h);
}

/* ── Sidebar ── */
#sidebar {
  width: var(--sidebar-w); min-width: var(--sidebar-w); max-width: var(--sidebar-w);
  background: var(--surface); border-right: 1px solid var(--border);
  display: flex; flex-direction: column; overflow: hidden;
}
#sidebar-search {
  padding: 8px; border-bottom: 1px solid var(--border);
}
#sidebar-search input {
  width: 100%; padding: 5px 8px; background: var(--surface2);
  border: 1px solid var(--border); border-radius: 6px; color: var(--text);
  font-size: 12px; outline: none;
}
#sidebar-search input:focus { border-color: var(--accent); }
#file-tree {
  flex: 1; overflow-y: auto; padding: 4px 0;
}
#file-tree::-webkit-scrollbar { width: 4px; }
#file-tree::-webkit-scrollbar-track { background: transparent; }
#file-tree::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }

.tree-dir, .tree-file {
  display: flex; align-items: center; gap: 6px; padding: 3px 8px;
  cursor: pointer; user-select: none; border-radius: 4px;
  transition: background .1s; white-space: nowrap; overflow: hidden;
}
.tree-dir:hover { background: rgba(255,255,255,.04); }
.tree-file:hover { background: rgba(255,255,255,.05); }
.tree-file.active { background: rgba(37,99,235,.25); color: var(--accent); }
.tree-name { overflow: hidden; text-overflow: ellipsis; font-size: 12px; }
.tree-dir .tree-name { font-weight: 600; color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: .04em; }
.tree-children { display: none; }
.tree-children.open { display: block; }
.tree-icon { font-size: 13px; flex-shrink: 0; }

/* Depth indentation */
.depth-0 { padding-left: 8px; }
.depth-1 { padding-left: 20px; }
.depth-2 { padding-left: 32px; }
.depth-3 { padding-left: 44px; }
.depth-4 { padding-left: 56px; }
.depth-5 { padding-left: 68px; }

/* ── Editor Area ── */
#editor-area {
  flex: 1; display: flex; flex-direction: column; overflow: hidden;
  background: #0d1117;
}
#editor-tabs {
  display: flex; align-items: center; background: var(--surface);
  border-bottom: 1px solid var(--border); overflow-x: auto; min-height: 34px;
}
#editor-tabs::-webkit-scrollbar { height: 3px; }
#editor-tabs::-webkit-scrollbar-thumb { background: var(--border); }
.tab {
  display: flex; align-items: center; gap: 6px; padding: 6px 12px;
  font-size: 11px; font-family: 'Consolas', monospace; cursor: pointer;
  border-right: 1px solid var(--border); color: var(--muted); white-space: nowrap;
  transition: background .1s; position: relative; min-width: 80px;
}
.tab:hover { background: rgba(255,255,255,.04); color: var(--text); }
.tab.active { background: var(--bg); color: var(--text); }
.tab.dirty::before {
  content: '●'; color: var(--yellow); font-size: 8px;
  position: absolute; top: 4px; right: 4px;
}
.tab-close { font-size: 12px; color: var(--muted); line-height: 1; padding: 1px 2px; border-radius: 2px; }
.tab-close:hover { background: rgba(255,255,255,.1); color: var(--text); }
#no-file-open {
  flex: 1; display: flex; flex-direction: column; align-items: center;
  justify-content: center; color: var(--muted); gap: 8px;
}
#no-file-open .big { font-size: 40px; }
#no-file-open .label { font-size: 13px; }
#no-file-open .hint { font-size: 11px; opacity: .6; }
#cm-wrap { flex: 1; overflow: hidden; display: none; }
.CodeMirror { height: 100% !important; font-family: 'Consolas','Monaco','Courier New',monospace !important; font-size: 13px !important; line-height: 1.6 !important; }
.CodeMirror-scroll { overflow: auto !important; }

/* ── Status Bar ── */
#statusbar {
  height: 24px; background: var(--surface); border-top: 1px solid var(--border);
  display: flex; align-items: center; padding: 0 12px; gap: 16px; font-size: 11px; color: var(--muted);
}
#statusbar span { white-space: nowrap; }

/* ── Notifications ── */
#toast {
  position: fixed; bottom: 20px; right: 20px; padding: 10px 18px;
  border-radius: 8px; font-size: 12px; font-weight: 600; z-index: 9999;
  opacity: 0; transform: translateY(10px); transition: all .25s;
  pointer-events: none;
}
#toast.show { opacity: 1; transform: translateY(0); }
#toast.ok  { background: var(--green); color: #000; }
#toast.err { background: var(--red); color: #fff; }
#toast.info { background: var(--primary); color: #fff; }
</style>
</head>
<body>

<!-- Top Bar -->
<div id="topbar">
  <div class="logo">⚡ File Editor</div>
  <div id="current-file">← Επέλεξε αρχείο από το sidebar</div>
  <div id="file-meta"></div>
  <button class="btn-top" id="btn-find" title="Find (Ctrl+F)" style="display:none">🔍 Find</button>
  <button class="btn-top" id="btn-back" onclick="location.href='/gopools/public/dashboard/'">← Dashboard</button>
  <button id="btn-save" disabled>💾 Save <small style="font-weight:400;font-size:10px">(Ctrl+S)</small></button>
  <div id="save-status"></div>
</div>

<div id="layout">
  <!-- Sidebar -->
  <div id="sidebar">
    <div id="sidebar-search">
      <input type="text" id="search-input" placeholder="🔍 Search files..." autocomplete="off">
    </div>
    <div id="file-tree">
      <div style="padding:20px;text-align:center;color:var(--muted)">Loading...</div>
    </div>
  </div>

  <!-- Editor Area -->
  <div id="editor-area">
    <div id="editor-tabs"></div>
    <div id="no-file-open">
      <div class="big">📝</div>
      <div class="label">Επέλεξε ένα αρχείο για επεξεργασία</div>
      <div class="hint">Ctrl+S για αποθήκευση · Ctrl+F για αναζήτηση</div>
    </div>
    <div id="cm-wrap"></div>
    <div id="statusbar">
      <span id="sb-mode">—</span>
      <span id="sb-pos">Ln 1, Col 1</span>
      <span id="sb-size">—</span>
      <span id="sb-mtime">—</span>
    </div>
  </div>
</div>

<div id="toast"></div>

<script>
const CSRF = <?php echo json_encode($csrf); ?>;

// ──────────────────────────────────────────────
// State
// ──────────────────────────────────────────────
let cm = null;
let openTabs = {}; // path → { content, dirty, mtime, size, ext }
let activeTab = null;

// ──────────────────────────────────────────────
// CodeMirror init
// ──────────────────────────────────────────────
function initEditor() {
  const wrap = document.getElementById('cm-wrap');
  const textarea = document.createElement('textarea');
  wrap.appendChild(textarea);
  cm = CodeMirror.fromTextArea(textarea, {
    theme: 'dracula',
    lineNumbers: true,
    matchBrackets: true,
    autoCloseBrackets: true,
    foldGutter: true,
    gutters: ['CodeMirror-linenumbers','CodeMirror-foldgutter'],
    indentUnit: 4,
    tabSize: 4,
    indentWithTabs: false,
    lineWrapping: false,
    extraKeys: {
      'Ctrl-S': saveActive,
      'Cmd-S':  saveActive,
      'Ctrl-F': () => { if (cm) cm.execCommand('find'); },
    }
  });
  cm.on('change', () => {
    if (activeTab && openTabs[activeTab]) {
      openTabs[activeTab].dirty = true;
      refreshTabs();
      document.getElementById('btn-save').disabled = false;
    }
  });
  cm.on('cursorActivity', updateStatusBar);
  wrap.style.display = 'flex';
  wrap.style.flexDirection = 'column';
  setTimeout(() => cm.refresh(), 100);
}

// ──────────────────────────────────────────────
// Mode detection
// ──────────────────────────────────────────────
function modeForExt(ext) {
  const map = { php:'application/x-httpd-php', js:'javascript', css:'css',
    html:'htmlmixed', xml:'xml', sql:'sql', md:'markdown',
    yml:'yaml', yaml:'yaml', json:'application/json', txt:'null' };
  return map[ext] || 'null';
}
function langLabel(ext) {
  const map = { php:'PHP', js:'JavaScript', css:'CSS', html:'HTML',
    xml:'XML', sql:'SQL', md:'Markdown', yml:'YAML', yaml:'YAML', json:'JSON', txt:'Text' };
  return map[ext] || ext.toUpperCase();
}

// ──────────────────────────────────────────────
// File Tree
// ──────────────────────────────────────────────
function loadTree() {
  fetch('/gopools/public/api/fe_tree.php')
    .then(r => r.json())
    .then(data => {
      if (!data.ok) { document.getElementById('file-tree').innerHTML = `<div style="padding:12px;color:var(--red)">${data.error}</div>`; return; }
      document.getElementById('file-tree').innerHTML = '';
      data.tree.forEach(node => renderNode(node, document.getElementById('file-tree'), 0));
    });
}

function renderNode(node, parent, depth) {
  if (node.type === 'dir') {
    const row = document.createElement('div');
    row.className = `tree-dir depth-${Math.min(depth,5)}`;
    row.dataset.path = node.path;
    row.innerHTML = `<span class="tree-icon">${depth === 0 ? '📁' : '▶'}</span><span class="tree-name" title="${node.path}">${node.name}</span>`;

    const children = document.createElement('div');
    children.className = 'tree-children';
    if (depth < 2) children.classList.add('open');

    (node.children || []).forEach(child => renderNode(child, children, depth + 1));
    row.appendChild(children);

    row.addEventListener('click', (e) => {
      e.stopPropagation();
      children.classList.toggle('open');
      const icon = row.querySelector('.tree-icon');
      icon.textContent = children.classList.contains('open') ? (depth===0?'📂':'▼') : (depth===0?'📁':'▶');
    });
    // Set initial icon
    if (children.classList.contains('open') && depth === 0) row.querySelector('.tree-icon').textContent = '📂';
    parent.appendChild(row);
  } else {
    const row = document.createElement('div');
    row.className = `tree-file depth-${Math.min(depth,5)}`;
    row.dataset.path = node.path;

    const icon = fileIcon(node.ext);
    const kb = node.size < 1024 ? node.size + ' B' : Math.round(node.size/1024) + ' KB';
    row.innerHTML = `<span class="tree-icon">${icon}</span><span class="tree-name" title="${node.path}">${node.name}</span>`;
    row.title = `${node.path} (${kb})`;
    row.addEventListener('click', (e) => { e.stopPropagation(); openFile(node.path, node.ext); });
    parent.appendChild(row);
  }
}

function fileIcon(ext) {
  const map = { php:'🐘', js:'📜', css:'🎨', html:'🌐', sql:'🗄️', json:'📋',
    md:'📝', yml:'⚙️', yaml:'⚙️', xml:'📄', txt:'📃', htaccess:'🔒' };
  return map[ext] || '📄';
}

// ──────────────────────────────────────────────
// Open File
// ──────────────────────────────────────────────
async function openFile(path, ext) {
  // Highlight sidebar
  document.querySelectorAll('.tree-file').forEach(el => el.classList.remove('active'));
  document.querySelectorAll(`.tree-file[data-path="${CSS.escape(path)}"]`).forEach(el => el.classList.add('active'));

  if (openTabs[path]) {
    switchTab(path);
    return;
  }

  try {
    const r = await fetch(`/gopools/public/api/fe_read.php?path=${encodeURIComponent(path)}`);
    const data = await r.json();
    if (!data.ok) { toast(data.error, 'err'); return; }

    openTabs[path] = { content: data.content, dirty: false, mtime: data.mtime, size: data.size, ext: data.ext || ext };
    if (!cm) initEditor();
    switchTab(path);
    toast('Opened: ' + path.split('/').pop(), 'info');
  } catch(e) { toast('Failed to open file', 'err'); }
}

// ──────────────────────────────────────────────
// Tabs
// ──────────────────────────────────────────────
function switchTab(path) {
  if (!openTabs[path]) return;
  activeTab = path;

  const tab = openTabs[path];
  if (cm) {
    cm.setValue(tab.content);
    cm.setOption('mode', modeForExt(tab.ext));
    cm.clearHistory();
    cm.refresh();
    setTimeout(() => cm.refresh(), 50);
  }

  document.getElementById('current-file').textContent = path;
  document.getElementById('file-meta').textContent = tab.mtime || '';
  document.getElementById('no-file-open').style.display = 'none';
  document.getElementById('cm-wrap').style.display = 'flex';
  document.getElementById('btn-save').disabled = !tab.dirty;
  document.getElementById('btn-find').style.display = '';

  updateStatusBar();
  refreshTabs();
}

function refreshTabs() {
  const tabBar = document.getElementById('editor-tabs');
  tabBar.innerHTML = '';
  Object.keys(openTabs).forEach(path => {
    const tab = openTabs[path];
    const el = document.createElement('div');
    el.className = 'tab' + (path === activeTab ? ' active' : '') + (tab.dirty ? ' dirty' : '');
    const name = path.split('/').pop();
    el.innerHTML = `<span class="tree-icon" style="font-size:11px">${fileIcon(tab.ext)}</span><span>${name}</span><span class="tab-close" data-path="${path}" title="Close">✕</span>`;
    el.addEventListener('click', (e) => {
      if (!e.target.classList.contains('tab-close')) switchTab(path);
    });
    el.querySelector('.tab-close').addEventListener('click', (e) => { e.stopPropagation(); closeTab(path); });
    tabBar.appendChild(el);
  });
}

function closeTab(path) {
  if (openTabs[path]?.dirty) {
    if (!confirm('Έχεις αποθηκεύσει; Αν κλείσεις θα χαθούν οι αλλαγές.')) return;
  }
  delete openTabs[path];
  if (activeTab === path) {
    const remaining = Object.keys(openTabs);
    if (remaining.length > 0) switchTab(remaining[remaining.length - 1]);
    else {
      activeTab = null;
      document.getElementById('no-file-open').style.display = 'flex';
      document.getElementById('cm-wrap').style.display = 'none';
      document.getElementById('current-file').textContent = '← Επέλεξε αρχείο από το sidebar';
      document.getElementById('btn-save').disabled = true;
      document.getElementById('btn-find').style.display = 'none';
    }
  }
  refreshTabs();
}

// ──────────────────────────────────────────────
// Save
// ──────────────────────────────────────────────
async function saveActive() {
  if (!activeTab || !cm || !openTabs[activeTab]) return;
  if (!openTabs[activeTab].dirty) { toast('No changes to save', 'info'); return; }

  const btn = document.getElementById('btn-save');
  btn.disabled = true;
  btn.textContent = '⏳ Saving...';

  const content = cm.getValue();
  try {
    const r = await fetch('/gopools/public/api/fe_save.php', {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({ path: activeTab, content, csrf_token: CSRF })
    });
    const data = await r.json();
    if (data.ok) {
      openTabs[activeTab].content = content;
      openTabs[activeTab].dirty = false;
      openTabs[activeTab].mtime = data.mtime;
      document.getElementById('file-meta').textContent = data.mtime;
      document.getElementById('save-status').textContent = '✅ Saved';
      setTimeout(() => document.getElementById('save-status').textContent = '', 3000);
      toast('✅ Αποθηκεύτηκε! (' + Math.round(data.bytes/1024*10)/10 + ' KB)', 'ok');
      refreshTabs();
    } else {
      toast('❌ ' + (data.error || 'Save failed'), 'err');
    }
  } catch(e) { toast('❌ Network error: ' + e.message, 'err'); }

  btn.textContent = '💾 Save';
  btn.disabled = !openTabs[activeTab]?.dirty;
}

document.getElementById('btn-save').addEventListener('click', saveActive);

// ──────────────────────────────────────────────
// Status Bar
// ──────────────────────────────────────────────
function updateStatusBar() {
  if (!cm || !activeTab) return;
  const cursor = cm.getCursor();
  const tab = openTabs[activeTab];
  document.getElementById('sb-pos').textContent = `Ln ${cursor.line+1}, Col ${cursor.ch+1}`;
  document.getElementById('sb-mode').textContent = langLabel(tab?.ext || '');
  document.getElementById('sb-size').textContent = tab ? (tab.size < 1024 ? tab.size + ' B' : Math.round(tab.size/1024) + ' KB') : '';
  document.getElementById('sb-mtime').textContent = tab?.mtime ? '🕐 ' + tab.mtime : '';
}

// ──────────────────────────────────────────────
// Search filter
// ──────────────────────────────────────────────
document.getElementById('search-input').addEventListener('input', function() {
  const q = this.value.toLowerCase().trim();
  document.querySelectorAll('.tree-file').forEach(el => {
    const match = !q || el.dataset.path.toLowerCase().includes(q);
    el.style.display = match ? '' : 'none';
    if (q && match) {
      let p = el.parentElement;
      while (p && p.id !== 'file-tree') {
        if (p.classList.contains('tree-children')) p.classList.add('open');
        p = p.parentElement;
      }
    }
  });
  if (!q) {
    document.querySelectorAll('.tree-dir .tree-children').forEach(el => {
      const depth = parseInt(el.closest('.tree-dir')?.className.match(/depth-(\d)/)?.[1] || 5);
      if (depth < 2) el.classList.add('open');
    });
  }
});

// ──────────────────────────────────────────────
// Toast notifications
// ──────────────────────────────────────────────
let toastTimer;
function toast(msg, type = 'ok') {
  const el = document.getElementById('toast');
  el.textContent = msg;
  el.className = `show ${type}`;
  clearTimeout(toastTimer);
  toastTimer = setTimeout(() => el.className = '', 3000);
}

// ──────────────────────────────────────────────
// Warn on close with unsaved changes
// ──────────────────────────────────────────────
window.addEventListener('beforeunload', (e) => {
  const hasDirty = Object.values(openTabs).some(t => t.dirty);
  if (hasDirty) { e.preventDefault(); e.returnValue = ''; }
});

// Find button
document.getElementById('btn-find').addEventListener('click', () => { if (cm) cm.execCommand('find'); });

// ──────────────────────────────────────────────
// Init
// ──────────────────────────────────────────────
loadTree();
</script>
</body>
</html>
