<?php
/* ======================================================================
   admin_publicidad.php — UN SOLO ARCHIVO (render + editor + API MySQL)
   - Usa tu db.php (pdo(): PDO) y PHP 8.2
   - Crea la tabla ad_items si no existe (una sola tabla)
   - Subidas a /uploads/publicidad/
   - En tus páginas: admin_publicidad('index');
   - Editar en vivo: agregá ?edit_ads=1 en la URL de esa página.
   ====================================================================== */

/* ========================== FUNCIÓN PÚBLICA ========================== */
function admin_publicidad(string $page_slug): void {
  $isEdit = isset($_GET['edit_ads']) && $_GET['edit_ads'] == '1';

  // Inyecta configuración + cliente
  $base = rtrim(dirname($_SERVER['SCRIPT_NAME'] ?? ''), '/');
  $self = $base.'/admin_publicidad.php';
  echo '<script>window.__ADS_CONF__={page:'.json_encode($page_slug).', api:'.json_encode($self).', edit:'.($isEdit?'true':'false').'};</script>';
  _ads_inject_css_js();
}

/* ========================== API (MISMO ARCHIVO) ========================== */
if (isset($_GET['ads']) || isset($_POST['ads'])) {
  header('Content-Type: application/json; charset=utf-8');
  require_once __DIR__.'/db.php';
  $pdo = pdo();
  $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  // 1) Asegurar tabla (MySQL)
  $pdo->exec("
    CREATE TABLE IF NOT EXISTS ad_items (
      id INT AUTO_INCREMENT PRIMARY KEY,
      page_slug VARCHAR(100) NOT NULL,
      type ENUM('image','video','html','link','section') NOT NULL,
      title VARCHAR(255) DEFAULT NULL,
      media_url TEXT NULL,
      link_url  TEXT NULL,
      html MEDIUMTEXT NULL,
      x_pct DOUBLE NOT NULL DEFAULT 10,
      y_pct DOUBLE NOT NULL DEFAULT 10,
      w_pct DOUBLE NOT NULL DEFAULT 30,
      h_pct DOUBLE NULL,
      zindex INT NOT NULL DEFAULT 10,
      is_active TINYINT(1) NOT NULL DEFAULT 1,
      created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
      updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      INDEX idx_page (page_slug),
      INDEX idx_active (is_active),
      INDEX idx_order (page_slug, zindex, id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  ");

  $act = $_GET['ads'] ?? $_POST['ads'] ?? '';

  $UPLOAD_DIR = $_SERVER['DOCUMENT_ROOT'].'/uploads/publicidad';
  $UPLOAD_URL = '/uploads/publicidad';
  if (!is_dir($UPLOAD_DIR)) @mkdir($UPLOAD_DIR, 0775, true);

  $json = function($ok,$extra=[],$code=200){ http_response_code($code); echo json_encode(['ok'=>$ok]+$extra, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); exit; };

  if ($act === 'list') {
    $page = $_GET['page'] ?? 'index';
    $st = $pdo->prepare("SELECT * FROM ad_items WHERE page_slug=? ORDER BY zindex ASC, id ASC");
    $st->execute([$page]);
    $rows = $st->fetchAll(PDO::FETCH_ASSOC);
    $json(true, ['items'=>$rows]);
  }

  if ($act === 'save') {
    $payload = json_decode($_POST['payload'] ?? '[]', true);
    if (!is_array($payload)) $payload = [];
    $now = date('Y-m-d H:i:s');

    $pdo->beginTransaction();
    try {
      foreach ($payload as $it) {
        $id   = (int)($it['id'] ?? 0);
        $page = (string)($it['page_slug'] ?? 'index');
        $type = (string)($it['type'] ?? 'image');
        $title= (string)($it['title'] ?? '');
        $media= (string)($it['media_url'] ?? '');
        $link = (string)($it['link_url'] ?? '');
        $html = (string)($it['html'] ?? '');
        $x    = (float)($it['x_pct'] ?? 10);
        $y    = (float)($it['y_pct'] ?? 10);
        $w    = (float)($it['w_pct'] ?? 30);
        $h    = array_key_exists('h_pct',$it) && $it['h_pct']!=='' ? (float)$it['h_pct'] : null;
        $z    = (int)($it['zindex'] ?? 10);
        $en   = (int)($it['is_active'] ?? 1);

        if ($id>0){
          $st=$pdo->prepare("UPDATE ad_items
            SET page_slug=?,type=?,title=?,media_url=?,link_url=?,html=?,x_pct=?,y_pct=?,w_pct=?,h_pct=?,zindex=?,is_active=?,updated_at=?
            WHERE id=?");
          $st->execute([$page,$type,$title,$media,$link,$html,$x,$y,$w,$h,$z,$en,$now,$id]);
          if ($st->rowCount()===0){
            $st=$pdo->prepare("INSERT INTO ad_items
              (page_slug,type,title,media_url,link_url,html,x_pct,y_pct,w_pct,h_pct,zindex,is_active,created_at,updated_at)
              VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
            $st->execute([$page,$type,$title,$media,$link,$html,$x,$y,$w,$h,$z,$en,$now,$now]);
          }
        } else {
          $st=$pdo->prepare("INSERT INTO ad_items
            (page_slug,type,title,media_url,link_url,html,x_pct,y_pct,w_pct,h_pct,zindex,is_active,created_at,updated_at)
            VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
          $st->execute([$page,$type,$title,$media,$link,$html,$x,$y,$w,$h,$z,$en,$now,$now]);
        }
      }
      $pdo->commit();
      $json(true, ['saved'=>count($payload)]);
    } catch(Throwable $e){
      $pdo->rollBack(); $json(false, ['error'=>$e->getMessage()], 500);
    }
  }

  if ($act === 'upload') {
    if (!isset($_FILES['file'])) $json(false, ['error'=>'Sin archivo'], 400);
    $f = $_FILES['file'];
    if ($f['error']!==UPLOAD_ERR_OK) $json(false, ['error'=>'Error de subida'], 400);
    $ext  = strtolower(pathinfo($f['name'], PATHINFO_EXTENSION));
    $safe = preg_replace('/[^a-zA-Z0-9_\.-]/','_', pathinfo($f['name'], PATHINFO_FILENAME));
    $name = $safe.'_'.date('Ymd_His').'.'.$ext;
    $dest = $UPLOAD_DIR.'/'.$name;
    if (!move_uploaded_file($f['tmp_name'], $dest)) $json(false, ['error'=>'No se pudo guardar'], 500);
    $json(true, ['url'=>$UPLOAD_URL.'/'.$name]);
  }

  // Acción inválida
  $json(false, ['error'=>'acción inválida'], 400);
}

/* ====================== INYECCIÓN CSS/JS (CLIENTE) ====================== */
function _ads_inject_css_js(): void {
  ?>
  <style>
    .ads-overlay{position:fixed;inset:0;pointer-events:none;z-index:2147483647}
    .ads-box{position:absolute;border:1px dashed #1f72b6;background:rgba(31,114,182,.07);border-radius:10px;overflow:hidden;pointer-events:auto}
    .ads-box.disabled{opacity:.45;filter:grayscale(.4)}
    .ads-bar{position:absolute;left:0;top:0;right:0;background:#1f72b6;color:#fff;padding:6px 8px;font:12px/1 system-ui;display:flex;justify-content:space-between;align-items:center;cursor:move}
    .ads-handle{position:absolute;right:0;bottom:0;padding:6px 8px;background:#1f72b6;color:#fff;font:12px/1 system-ui;border-top-left-radius:8px;cursor:nwse-resize}
    .ads-ghost{outline:2px dashed rgba(31,114,182,.6); outline-offset:2px}
    .ads-panel{position:fixed;top:0;right:0;width:340px;height:100vh;background:#fff;border-left:1px solid #e6eaf0;box-shadow:-12px 0 30px rgba(15,26,36,.06);z-index:2147483647;padding:12px;display:flex;flex-direction:column;gap:10px}
    .ads-panel h3{margin:4px 0 2px;font:600 13px/1.2 system-ui;color:#0f1a24}
    .ads-input{width:100%;border:1px solid #dbe3ed;border-radius:10px;padding:8px 10px;font:14px system-ui}
    .ads-row{display:grid;grid-template-columns:1fr 1fr;gap:8px}
    .ads-btn{border:1px solid #cfd8e3;background:#fff;border-radius:10px;padding:8px 10px;cursor:pointer}
    .ads-btn.primary{background:#1f72b6;color:#fff;border-color:#1f72b6}
    .ads-list{overflow:auto;border:1px solid #edf0f5;border-radius:10px;padding:8px;max-height:32vh}
    .ads-item{display:flex;justify-content:space-between;gap:8px;border:1px solid #edf0f5;border-radius:10px;padding:6px 8px;margin-bottom:6px}
    .ads-hint{font:12px/1.4 system-ui;color:#6b7480}
  </style>
  <script>
  (() => {
    const CFG = window.__ADS_CONF__ || {page:'index', api:'admin_publicidad.php', edit:false};
    const $ = (s, r=document) => r.querySelector(s);
    const el = (t, p={}) => Object.assign(document.createElement(t), p);
    const clamp = v => Math.max(0, Math.min(100, v));
    const j = (u,o) => fetch(u,o).then(r=>r.json());

    let items=[], selected=null;
    const overlay = el('div',{className:'ads-overlay'});
    document.addEventListener('DOMContentLoaded', ()=> document.body.appendChild(overlay));

    function drawAll(){ overlay.innerHTML=''; items.forEach(draw); }
    function draw(it){
      const box=el('div',{className:'ads-box'+(it.is_active?'':' disabled')}); box.dataset.id=it.id;
      Object.assign(box.style,{left:it.x_pct+'%',top:it.y_pct+'%',width:it.w_pct+'%',height:(it.h_pct!=null?it.h_pct+'%':''),zIndex:it.zindex});
      const content=el('div'); Object.assign(content.style,{position:'relative',width:'100%',height:'100%'});

      if(it.type==='section'){
        content.innerHTML = `<div style="position:absolute;inset:0;background:#15324c;color:#fff;display:flex;align-items:center;padding:12px 16px;font-weight:700;border-radius:8px">${it.title||'Sección'}</div>`;
      } else if(it.type==='image' && it.media_url){
        content.innerHTML = `<img src="${it.media_url}" style="width:100%;height:100%;object-fit:contain;display:block">`;
      } else if(it.type==='video'){
        const mu=it.media_url||'';
        if(/youtu\.?be/.test(mu)){
          const m=mu.match(/(?:v=|\.be\/)([\\w-]+)/); const id=m&&m[1]||'';
          content.innerHTML = id ? `<iframe src="https://www.youtube.com/embed/${id}" allow="autoplay;encrypted-media" allowfullscreen style="width:100%;height:100%;border:0"></iframe>` : `<div style="padding:12px">URL YouTube inválida</div>`;
        } else if (mu){
          content.innerHTML = `<video src="${mu}" controls style="width:100%;height:100%;object-fit:cover"></video>`;
        }
      } else if(it.type==='html'){
        content.innerHTML = it.html||'';
      } else if(it.type==='link'){
        const label=it.title||it.link_url||'Link', href=it.link_url||'#';
        content.innerHTML = `<a href="${href}" target="_blank" style="position:absolute;inset:8px;display:flex;align-items:center;justify-content:center;border:2px dashed #1f72b6;border-radius:8px;text-decoration:none;color:#1f72b6;font-weight:600;background:#fff">${label}</a>`;
      }

      if (CFG.edit){
        const bar=el('div',{className:'ads-bar'}); 
        bar.innerHTML = `<div><b>${it.type}</b> <span style="opacity:.85">${it.title||''}</span></div>
                         <div style="display:flex;gap:6px">
                           <button class="ads-btn" data-act="zup">▲</button>
                           <button class="ads-btn" data-act="zdown">▼</button>
                           <button class="ads-btn" data-act="toggle">on/off</button>
                           <button class="ads-btn" data-act="del">🗑</button>
                         </div>`;
        const handle=el('div',{className:'ads-handle',textContent:'↘'});
        box.append(bar,content,handle);

        box.addEventListener('pointerdown', e=>{ select(it.id); e.stopPropagation(); });
        bar.addEventListener('pointerdown', e=> startDrag(it,box,e));
        handle.addEventListener('pointerdown', e=> startResize(it,box,e));
        bar.addEventListener('click', (e)=>{
          const b=e.target.closest('button'); if(!b) return; const a=b.dataset.act;
          if(a==='del'){ if(confirm('¿Eliminar?')){ items=items.filter(x=>x.id!==it.id); drawAll(); buildList(); if(selected===it.id) selected=null; } }
          if(a==='toggle'){ it.is_active=it.is_active?0:1; drawAll(); buildList(); highlight(); }
          if(a==='zup'){ it.zindex++; drawAll(); buildList(); highlight(); }
          if(a==='zdown'){ it.zindex=Math.max(0, it.zindex-1); drawAll(); buildList(); highlight(); }
        });
      } else {
        box.append(content);
      }

      overlay.appendChild(box);
    }

    function select(id){ selected=id; highlight(); buildProps(); }
    function highlight(){ overlay.querySelectorAll('.ads-box').forEach(n=> n.classList.toggle('ads-ghost', +n.dataset.id===selected)); }

    // drag/resize
    let drag=null, rez=null;
    function R(){ const r=overlay.getBoundingClientRect(); return {W:r.width,H:r.height}; }
    function startDrag(it, el, ev){ ev.preventDefault(); const {W,H}=R(); drag={it,el,sx:ev.clientX,sy:ev.clientY,ox:it.x_pct,oy:it.y_pct,W,H}; window.addEventListener('pointermove',onDrag); window.addEventListener('pointerup',endDrag,{once:true}); }
    function onDrag(ev){ if(!drag) return; const speed=ev.shiftKey?2:1; const dx=(ev.clientX-drag.sx)*speed, dy=(ev.clientY-drag.sy)*speed; let nx=drag.ox+(dx/drag.W)*100, ny=drag.oy+(dy/drag.H)*100; drag.it.x_pct=clamp(nx); drag.it.y_pct=clamp(ny); Object.assign(drag.el.style,{left:drag.it.x_pct+'%', top:drag.it.y_pct+'%'}); }
    function endDrag(){ window.removeEventListener('pointermove', onDrag); drag=null; buildProps(); }
    function startResize(it, el, ev){ ev.preventDefault(); const {W,H}=R(); rez={it,el,sx:ev.clientX,sy:ev.clientY,ow:it.w_pct,oh:it.h_pct??null,W,H}; window.addEventListener('pointermove',onResize); window.addEventListener('pointerup',endResize,{once:true}); }
    function onResize(ev){ if(!rez) return; const dx=ev.clientX-rez.sx, dy=ev.clientY-rez.sy; let nw=rez.ow+(dx/rez.W)*100; nw=Math.max(5, clamp(nw)); rez.it.w_pct=nw; if(rez.it.h_pct!=null){ let nh=(rez.oh??rez.it.h_pct)+(dy/rez.H)*100; nh=Math.max(5, clamp(nh)); rez.it.h_pct=nh; } drawAll(); select(rez.it.id); }
    function endResize(){ window.removeEventListener('pointermove', onResize); rez=null; buildProps(); }

    // Panel de edición
    let panel, uploader;
    function mountPanel(){
      if(!CFG.edit) return;
      panel=el('div',{className:'ads-panel'});
      panel.innerHTML = `
        <div style="display:flex;gap:6px">
          <button class="ads-btn" data-add="section">Section</button>
          <button class="ads-btn" data-add="image">Imagen</button>
          <button class="ads-btn" data-add="video">Video</button>
          <button class="ads-btn" data-add="html">HTML</button>
          <button class="ads-btn" data-add="link">Link</button>
        </div>
        <h3>Propiedades</h3>
        <div id="ads-props" class="ads-hint">Seleccioná un bloque</div>
        <h3>Listado</h3>
        <div id="ads-list" class="ads-list"></div>
        <div style="display:flex;gap:8px;margin-top:auto">
          <button class="ads-btn" id="ads-reload">Recargar</button>
          <button class="ads-btn primary" id="ads-save">Guardar</button>
        </div>
        <input id="ads-upload" type="file" hidden accept="image/*,video/*">
        <div class="ads-hint" style="margin-top:6px">Arrastrá para mover, ↘ redimensiona. Shift rápido, Alt micro. PageUp/Down cambia Z. Supr borra.</div>
      `;
      document.body.appendChild(panel);
      panel.querySelectorAll('[data-add]').forEach(b=> b.addEventListener('click', ()=> addItem(b.dataset.add)));
      $('#ads-reload').onclick=load;
      $('#ads-save').onclick=save;
      uploader = $('#ads-upload');
    }

    function addItem(type){
      const it={ id:0, page_slug:CFG.page, type, title:'', media_url:'', link_url:'', html:'', x_pct:10, y_pct:10, w_pct:30, h_pct:(type==='section'?12:null), zindex:10, is_active:1 };
      if(type==='link'){ it.title='Ver más'; it.link_url='#'; it.w_pct=15; }
      if(type==='video'){ it.w_pct=35; }
      if(type==='section'){ it.title='Sección'; it.x_pct=0; it.w_pct=100; it.zindex=5; }
      items.push(it); drawAll(); buildList(); select(it.id);
    }

    function buildList(){
      if(!CFG.edit) return; const list=$('#ads-list'); if(!list) return;
      list.innerHTML = items.map(i=>`
        <div class="ads-item">
          <div><b>#${i.id}</b> <span style="opacity:.7">${i.type}</span> ${i.title? '— '+i.title:''}</div>
          <div style="display:flex;gap:6px">
            <button class="ads-btn" data-jump="${i.id}">Ir</button>
            <button class="ads-btn" data-del="${i.id}">🗑</button>
          </div>
        </div>`).join('') || '<div class="ads-hint">No hay bloques.</div>';
      list.querySelectorAll('[data-jump]').forEach(b=> b.onclick=()=> select(+b.dataset.jump));
      list.querySelectorAll('[data-del]').forEach(b=> b.onclick=()=>{ const id=+b.dataset.del; if(confirm('¿Eliminar?')){ items=items.filter(i=>i.id!==id); drawAll(); buildList(); if(selected===id) selected=null; }});
    }

    function buildProps(){
      if(!CFG.edit) return; const box=$('#ads-props'); if(!box) return;
      const it=items.find(i=>i.id===selected);
      if(!it){ box.innerHTML='<span class="ads-hint">Seleccioná un bloque</span>'; return; }

      let spec='';
      if(it.type!=='html'){
        spec += `<div class="ads-row" style="grid-template-columns:1fr auto">
          <input id="p_media" class="ads-input" placeholder="Media URL" value="${it.media_url||''}">
          <button class="ads-btn" id="p_upload">Subir</button>
        </div>`;
      }
      if(it.type==='video'){ spec += `<div class="ads-hint">YouTube (https://youtu.be/ID o ?v=ID) o MP4 subido.</div>`; }
      if(it.type==='link' || it.type==='image'){ spec += `<input id="p_link" class="ads-input" placeholder="Link URL" value="${it.link_url||''}">`; }
      if(it.type==='html'){ spec += `<textarea id="p_html" class="ads-input" style="min-height:120px">${(it.html||'').replaceAll('<','&lt;')}</textarea>`; }

      box.innerHTML = `
        <input id="p_title" class="ads-input" placeholder="Título / Label" value="${it.title||''}">
        ${spec}
        <div class="ads-row">
          <div><div class="ads-hint">X%</div><input id="p_x" class="ads-input" value="${it.x_pct}"></div>
          <div><div class="ads-hint">Y%</div><input id="p_y" class="ads-input" value="${it.y_pct}"></div>
        </div>
        <div class="ads-row">
          <div><div class="ads-hint">W%</div><input id="p_w" class="ads-input" value="${it.w_pct}"></div>
          <div><div class="ads-hint">H% (vacío=auto)</div><input id="p_h" class="ads-input" value="${it.h_pct??''}"></div>
        </div>
        <div class="ads-row">
          <div><div class="ads-hint">Z</div><input id="p_z" class="ads-input" value="${it.zindex}"></div>
          <div><div class="ads-hint">Activo</div>
            <select id="p_en" class="ads-input">
              <option value="1" ${it.is_active? 'selected':''}>Sí</option>
              <option value="0" ${!it.is_active? 'selected':''}>No</option>
            </select>
          </div>
        </div>
        <div style="display:flex;gap:8px;margin-top:6px">
          <button class="ads-btn primary" id="p_apply">Aplicar</button>
        </div>`;

      $('#p_upload')?.addEventListener('click', ()=>{ uploader.value=''; uploader.click(); });
      if (uploader){
        uploader.onchange = async () => {
          const f=uploader.files?.[0]; if(!f) return;
          const fd=new FormData(); fd.append('ads','upload'); fd.append('file',f);
          const js=await j(CFG.api, {method:'POST', body:fd});
          if (js.ok){ it.media_url=js.url; buildProps(); drawAll(); select(it.id); } else alert(js.error||'Upload fail');
        };
      }

      $('#p_apply').onclick = () => {
        it.title = $('#p_title')?.value||'';
        if (it.type!=='html') it.media_url = $('#p_media')?.value||'';
        if (it.type==='link' || it.type==='image') it.link_url = $('#p_link')?.value||'';
        if (it.type==='html') it.html = ($('#p_html')?.value||'').replaceAll('&lt;','<');
        it.x_pct = +($('#p_x')?.value||it.x_pct);
        it.y_pct = +($('#p_y')?.value||it.y_pct);
        it.w_pct = +($('#p_w')?.value||it.w_pct);
        const hv = $('#p_h')?.value; it.h_pct = hv===''? null : +hv;
        it.zindex = +($('#p_z')?.value||it.zindex);
        it.is_active = +($('#p_en')?.value||it.is_active);
        drawAll(); buildList();
      };
    }

    // teclado
    window.addEventListener('keydown',(e)=>{
      if(!CFG.edit || selected==null) return;
      const it=items.find(i=>i.id===selected); if(!it) return;
      const step = e.altKey?0.2:(e.shiftKey?5:1);
      if(['ArrowLeft','ArrowRight','ArrowUp','ArrowDown','Delete','PageUp','PageDown'].includes(e.key)) e.preventDefault();
      if(e.key==='ArrowLeft'){ if(e.ctrlKey) it.w_pct=Math.max(5, clamp(it.w_pct-step)); else it.x_pct=clamp(it.x_pct-step); }
      if(e.key==='ArrowRight'){ if(e.ctrlKey) it.w_pct=Math.max(5, clamp(it.w_pct+step)); else it.x_pct=clamp(it.x_pct+step); }
      if(e.key==='ArrowUp'){ if(e.ctrlKey && it.h_pct!=null) it.h_pct=Math.max(5, clamp((it.h_pct||0)-step)); else it.y_pct=clamp(it.y_pct-step); }
      if(e.key==='ArrowDown'){ if(e.ctrlKey && it.h_pct!=null) it.h_pct=Math.max(5, clamp((it.h_pct||0)+step)); else it.y_pct=clamp(it.y_pct+step); }
      if(e.key==='Delete'){ items = items.filter(x=>x.id!==it.id); selected=null; }
      if(e.key==='PageUp'){ it.zindex++; }
      if(e.key==='PageDown'){ it.zindex=Math.max(0, it.zindex-1); }
      drawAll(); buildList(); buildProps();
    });

    // CRUD
    async function load(){
      const js = await j(CFG.api+'?ads=list&page='+encodeURIComponent(CFG.page));
      items = (js.items||[]).map(r => ({
        ...r, id:+r.id||r.id,
        x_pct:+r.x_pct, y_pct:+r.y_pct, w_pct:+r.w_pct,
        h_pct:r.h_pct===null?null:+r.h_pct,
        zindex:+r.zindex, is_active:+r.is_active
      }));
      drawAll();
      if (CFG.edit){ mountPanel(); buildList(); buildProps(); }
    }
    async function save(){
      const fd=new FormData();
      fd.append('ads','save');
      fd.append('payload', JSON.stringify(items.map(i=>({
        id:i.id, page_slug:CFG.page, type:i.type, title:i.title,
        media_url:i.media_url, link_url:i.link_url, html:i.html,
        x_pct:i.x_pct, y_pct:i.y_pct, w_pct:i.w_pct, h_pct:i.h_pct,
        zindex:i.zindex, is_active:i.is_active
      }))));
      const js=await j(CFG.api, {method:'POST', body:fd});
      if(js.ok){ alert('Guardado'); await load(); } else alert(js.error||'Error al guardar');
    }

    let uploader;
    document.addEventListener('DOMContentLoaded', async ()=>{
      await load();
      if (CFG.edit){ uploader = document.getElementById('ads-upload'); }
    });
  })();
  </script>
  <?php
}
