(function(){
'use strict';
const API='https://epictravelexpeditions.com/api';

function authHdr(){return{'Content-Type':'application/json',Authorization:`Bearer ${localStorage.getItem('auth_token')}`};}
async function api(path,opts){
  const res=await fetch(API+path,{headers:authHdr(),...opts});
  const d=await res.json();
  if(!res.ok)throw new Error(d.error||res.statusText);
  return d;
}
async function uploadImg(file){
  const fd=new FormData();fd.append('file',file);
  const res=await fetch(API+'/upload/image',{method:'POST',headers:{Authorization:`Bearer ${localStorage.getItem('auth_token')}`},body:fd});
  const d=await res.json();
  if(!res.ok)throw new Error(d.error||'Upload failed');
  return d.url;
}
async function getImg(inputId,fallback){
  const el=document.getElementById(inputId);
  if(el&&el.files&&el.files[0]){
    const st=document.getElementById(inputId+'-st');
    if(st)st.textContent='Uploading…';
    try{const url=await uploadImg(el.files[0]);if(st)st.textContent='';return url;}
    catch(e){if(st){st.textContent='Upload failed: '+e.message;st.style.color='#dc2626';}throw e;}
  }
  return fallback!=null?fallback:null;
}
function imgPicker(id,src){
  const pr=src
    ?`<img id="${id}-pr" src="${src}" style="width:52px;height:52px;border-radius:8px;object-fit:cover;border:1px solid #e5e7eb">`
    :`<div id="${id}-pr" style="width:52px;height:52px;border-radius:8px;background:#f3f4f6;border:1px solid #e5e7eb;display:flex;align-items:center;justify-content:center;font-size:20px">🖼</div>`;
  return `<div style="display:flex;align-items:center;gap:10px">${pr}<label style="display:inline-flex;align-items:center;gap:6px;padding:7px 13px;border:1px dashed #d1d5db;border-radius:7px;cursor:pointer;font-size:12px;color:#6b7280;background:#fff">📁 Choose Image<input type="file" accept="image/jpeg,image/png,image/webp" id="${id}" style="display:none" onchange="(function(el){const f=el.files[0];if(!f)return;const u=URL.createObjectURL(f);const p=document.getElementById('${id}-pr');if(p.tagName==='IMG'){p.src=u;}else{p.outerHTML='<img id=${id}-pr src='+u+' style=width:52px;height:52px;border-radius:8px;object-fit:cover;border:1px solid #e5e7eb>';};})(this)"></label><span id="${id}-st" style="font-size:11px;color:#6b7280"></span></div>`;
}

function daysAgo(s){return Math.floor((Date.now()-new Date(s))/86400000);}
function daysLeft(s){return Math.ceil((new Date(s)-Date.now())/86400000);}
function ageBdg(d){const c=d<30?'bg':d<90?'by':'br';return`<span class="ep-b ${c}">${d}d ago</span>`;}
function expBdg(d){if(d<0)return`<span class="ep-b br">Expired</span>`;const c=d>14?'bg':d>7?'by':'br';return`<span class="ep-b ${c}">${d}d left</span>`;}
function esc(s){const e=document.createElement('div');e.textContent=s||'';return e.innerHTML;}
function catOpts(cats,sel){return cats.map(c=>`<option value="${esc(c.name)}"${c.name===sel?' selected':''}>${esc(c.name)}</option>`).join('');}
function fmtPrice(p){return p!=null?'$'+parseFloat(p).toLocaleString(undefined,{minimumFractionDigits:0,maximumFractionDigits:2}):'';}

/* CSS */
const css=`
#ep-portal{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;color:#111827;min-height:100vh;background:#f3f4f6}
#ep-portal *,#ep-portal *::before,#ep-portal *::after{box-sizing:border-box}
#ep-hdr{background:#fff;border-bottom:1px solid #e5e7eb;padding:0 28px;height:60px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100;box-shadow:0 1px 3px rgba(0,0,0,.06)}
.ep-logo{font-size:17px;font-weight:800;color:#1d4ed8;letter-spacing:-.4px}.ep-logo span{color:#6b7280;font-weight:400}
.ep-hdr-acts{display:flex;gap:8px}
.ep-hbtn{padding:6px 14px;border-radius:7px;font-size:13px;font-weight:600;border:1px solid #d1d5db;background:#fff;color:#374151;cursor:pointer;transition:all .15s;text-decoration:none;display:inline-flex;align-items:center;gap:5px}
.ep-hbtn:hover{background:#f9fafb}.ep-hbtn.red{border-color:#fca5a5;color:#dc2626}.ep-hbtn.red:hover{background:#fef2f2}
#ep-tabs{background:#fff;border-bottom:1px solid #e5e7eb;padding:0 28px;display:flex;gap:2px}
.ep-tab{padding:13px 18px;font-size:13px;font-weight:600;color:#6b7280;border:none;background:none;cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px;transition:all .15s;display:inline-flex;align-items:center;gap:7px}
.ep-tab:hover{color:#1d4ed8}.ep-tab.active{color:#1d4ed8;border-bottom-color:#1d4ed8}
.ep-tbadge{background:#fee2e2;color:#dc2626;border-radius:999px;font-size:11px;padding:1px 6px;font-weight:700}
#ep-body{padding:28px;max-width:1180px;margin:0 auto}
.ep-g4{display:grid;grid-template-columns:repeat(4,1fr);gap:18px;margin-bottom:28px}
@media(max-width:880px){.ep-g4{grid-template-columns:repeat(2,1fr)}}
.ep-stat{background:#fff;border:1px solid #e5e7eb;border-radius:12px;padding:20px 22px;position:relative;overflow:hidden}
.ep-si{font-size:26px;margin-bottom:6px}.ep-sv{font-size:30px;font-weight:800;color:#111827}.ep-sl{font-size:12px;color:#6b7280;margin-top:1px}
.ep-acc{position:absolute;right:0;top:0;bottom:0;width:4px;border-radius:0 12px 12px 0}
.acb{background:#3b82f6}.acg{background:#10b981}.aca{background:#f59e0b}.acp{background:#8b5cf6}
.ep-card{background:#fff;border:1px solid #e5e7eb;border-radius:12px;margin-bottom:22px;overflow:hidden}
.ep-ch{padding:16px 22px;border-bottom:1px solid #e5e7eb;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px}
.ep-ct{font-size:14px;font-weight:700;color:#111827}.ep-cs{font-size:12px;color:#6b7280;margin-top:1px}
.ep-cb{padding:22px}
.ep-tbl{width:100%;border-collapse:collapse;font-size:13px}
.ep-tbl th{text-align:left;font-size:11px;font-weight:700;color:#6b7280;text-transform:uppercase;letter-spacing:.05em;padding:9px 12px;border-bottom:1px solid #e5e7eb;white-space:nowrap}
.ep-tbl td{padding:11px 12px;border-bottom:1px solid #f3f4f6;vertical-align:middle}
.ep-tbl tr:last-child td{border-bottom:none}.ep-tbl tr:hover td{background:#fafafa}
.ep-b{display:inline-block;padding:2px 9px;border-radius:999px;font-size:11px;font-weight:700}
.bg{background:#d1fae5;color:#065f46}.by{background:#fef3c7;color:#92400e}.br{background:#fee2e2;color:#991b1b}.bb{background:#dbeafe;color:#1e40af}.bgr{background:#f3f4f6;color:#374151}
.ep-btn{padding:6px 13px;border-radius:7px;font-size:12px;font-weight:600;border:none;cursor:pointer;transition:opacity .15s;display:inline-flex;align-items:center;gap:4px;white-space:nowrap}
.ep-btn:hover{opacity:.82}.ep-btn:disabled{opacity:.4;cursor:not-allowed}
.ep-pri{background:#2563eb;color:#fff}.ep-suc{background:#16a34a;color:#fff}.ep-dan{background:#dc2626;color:#fff}.ep-gho{background:#f3f4f6;color:#374151}
.ep-form{display:grid;grid-template-columns:1fr 1fr;gap:14px}
@media(max-width:640px){.ep-form{grid-template-columns:1fr}}
.ep-full{grid-column:1/-1}.ep-fld{display:flex;flex-direction:column;gap:4px}
.ep-lbl{font-size:11px;font-weight:700;color:#374151;text-transform:uppercase;letter-spacing:.04em}
.ep-inp,.ep-sel,.ep-ta{padding:8px 11px;border:1px solid #d1d5db;border-radius:7px;font-size:13px;color:#111827;background:#fff;outline:none;transition:border-color .15s;width:100%}
.ep-inp:focus,.ep-sel:focus,.ep-ta:focus{border-color:#3b82f6;box-shadow:0 0 0 3px rgba(59,130,246,.1)}
.ep-ta{resize:vertical;min-height:72px}
.ep-frow{grid-column:1/-1;display:flex;gap:10px;justify-content:flex-end;padding-top:4px;align-items:center}
.ep-addbox{border:1px dashed #d1d5db;border-radius:10px;padding:18px;margin-bottom:20px;background:#fafafa;display:none}
.ep-addbox.open{display:block}
.ep-thumb{width:40px;height:40px;border-radius:7px;object-fit:cover;background:#e5e7eb}
.ep-smsg{font-size:12px}.ep-smsg.ok{color:#16a34a}.ep-smsg.err{color:#dc2626}
.ep-alert{padding:10px 15px;border-radius:8px;font-size:13px;margin-bottom:16px;border-left:3px solid}
.ep-alert.warn{background:#fffbeb;color:#92400e;border-color:#f59e0b}
.ep-inline{display:grid;grid-template-columns:1fr 1fr;gap:10px;padding:14px}
@media(max-width:640px){.ep-inline{grid-column:1fr}}
.ep-cat-row{display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:8px;border:1px solid #e5e7eb;background:#fff;margin-bottom:8px}
.ep-cat-nm{flex:1;font-size:13px;font-weight:600}.ep-cat-ct{font-size:11px;color:#9ca3af}
.ep-cat-ei{flex:1;padding:5px 9px;border:1px solid #3b82f6;border-radius:6px;font-size:13px;outline:none}
.ep-tc{border:1px solid #e5e7eb;border-radius:10px;padding:16px;margin-bottom:12px;display:flex;gap:12px;background:#fff}
.ep-tav{width:42px;height:42px;border-radius:50%;object-fit:cover;flex-shrink:0;background:#e5e7eb}
.ep-tavph{width:42px;height:42px;border-radius:50%;background:#2563eb;color:#fff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:16px;flex-shrink:0}
.ep-tb{flex:1;min-width:0}.ep-tn{font-weight:700;font-size:13px}.ep-tl{font-size:11px;color:#6b7280;margin-bottom:5px}
.ep-tm{font-size:13px;color:#374151;margin-bottom:8px;line-height:1.5}
.ep-te{width:100%;border:1px solid #d1d5db;border-radius:6px;padding:6px 9px;font-size:12px;margin-bottom:7px;resize:vertical;min-height:52px}
.ep-tacts{display:flex;gap:7px;flex-wrap:wrap}
.ep-ftabs{display:flex;gap:7px;margin-bottom:18px;flex-wrap:wrap}
.ep-ft{padding:6px 15px;border-radius:7px;font-size:12px;font-weight:600;cursor:pointer;border:1px solid #d1d5db;background:#fff;color:#374151;transition:all .15s}
.ep-ft.active{background:#2563eb;color:#fff;border-color:#2563eb}
.ep-empty{text-align:center;padding:36px;color:#9ca3af;font-size:13px}
.ep-spec-img{width:52px;height:52px;border-radius:8px;object-fit:cover;background:#e5e7eb;flex-shrink:0}
.ep-price-old{text-decoration:line-through;color:#9ca3af;font-size:11px}
.ep-price-new{color:#16a34a;font-weight:700}
`;
const sel=document.createElement('style');sel.textContent=css;document.head.appendChild(sel);

/* State */
let activeTab='dashboard',tFilter='pending';
let destinations=[],specials=[],testimonials=[],categories=[];

async function loadAll(){
  const r=await Promise.allSettled([
    fetch(API+'/destinations',{headers:authHdr()}).then(r=>r.json()),
    fetch(API+'/specials',    {headers:authHdr()}).then(r=>r.json()),
    fetch(API+'/testimonials/all',{headers:authHdr()}).then(r=>r.json()),
    fetch(API+'/categories',  {headers:authHdr()}).then(r=>r.json())
  ]);
  if(r[0].status==='fulfilled'&&Array.isArray(r[0].value))destinations=r[0].value;
  if(r[1].status==='fulfilled'&&Array.isArray(r[1].value))specials=r[1].value;
  if(r[2].status==='fulfilled'&&Array.isArray(r[2].value))testimonials=r[2].value;
  if(r[3].status==='fulfilled'&&Array.isArray(r[3].value))categories=r[3].value;
}

/* Shell */
function buildShell(){
  const p=document.createElement('div');p.id='ep-portal';
  p.innerHTML=`
    <div id="ep-hdr">
      <div class="ep-logo">Epic Travel <span>Admin</span></div>
      <div class="ep-hdr-acts">
        <a href="/" class="ep-hbtn" target="_blank">🌐 View Site</a>
        <button class="ep-hbtn red" id="ep-logout">⏻ Logout</button>
      </div>
    </div>
    <div id="ep-tabs">
      <button class="ep-tab active" data-tab="dashboard">📊 Dashboard</button>
      <button class="ep-tab" data-tab="destinations">🗺 Destinations</button>
      <button class="ep-tab" data-tab="specials">⭐ Specials</button>
      <button class="ep-tab" data-tab="testimonials">💬 Testimonials <span class="ep-tbadge" id="ep-pb" style="display:none"></span></button>
    </div>
    <div id="ep-body"></div>`;
  p.querySelector('#ep-logout').onclick=()=>{localStorage.removeItem('isAdminAuthenticated');localStorage.removeItem('auth_token');window.location.href='/admin';};
  p.querySelectorAll('.ep-tab[data-tab]').forEach(b=>{b.onclick=()=>{activeTab=b.dataset.tab;p.querySelectorAll('.ep-tab').forEach(t=>t.classList.remove('active'));b.classList.add('active');render();};});
  return p;
}

/* Dashboard */
function rDash(){
  const dm=Object.fromEntries(destinations.map(d=>[d.id,d]));
  const pen=testimonials.filter(t=>t.status==='pending').length;
  const app=testimonials.filter(t=>t.status==='approved').length;
  let h=`<div class="ep-g4">
    <div class="ep-stat"><div class="ep-acc acb"></div><div class="ep-si">🗺</div><div class="ep-sv">${destinations.length}</div><div class="ep-sl">Destinations</div></div>
    <div class="ep-stat"><div class="ep-acc acg"></div><div class="ep-si">⭐</div><div class="ep-sv">${specials.length}</div><div class="ep-sl">Active Specials</div></div>
    <div class="ep-stat"><div class="ep-acc aca"></div><div class="ep-si">⏳</div><div class="ep-sv">${pen}</div><div class="ep-sl">Pending Reviews</div></div>
    <div class="ep-stat"><div class="ep-acc acp"></div><div class="ep-si">✅</div><div class="ep-sv">${app}</div><div class="ep-sl">Approved Testimonials</div></div>
  </div>`;
  if(pen>0)h+=`<div class="ep-alert warn">⚠️ <strong>${pen}</strong> testimonial${pen>1?'s':''} awaiting review.</div>`;

  /* Destinations age */
  const sd=[...destinations].sort((a,b)=>new Date(a.created_at)-new Date(b.created_at));
  h+=`<div class="ep-card"><div class="ep-ch"><div><div class="ep-ct">🗺 Destinations</div><div class="ep-cs">Oldest entries first</div></div></div><table class="ep-tbl"><thead><tr><th>Destination</th><th>Category</th><th>Price</th><th>In System Since</th></tr></thead><tbody>`;
  sd.forEach(d=>{h+=`<tr><td><strong>${esc(d.name)}</strong> <span style="color:#9ca3af;font-size:11px">${esc(d.location)}</span></td><td><span class="ep-b bb">${esc(d.category)}</span></td><td>${fmtPrice(d.price)}</td><td>${ageBdg(daysAgo(d.created_at))}</td></tr>`;});
  h+=`</tbody></table></div>`;

  /* Specials expiry */
  const ss=[...specials].sort((a,b)=>new Date(a.end_date)-new Date(b.end_date));
  h+=`<div class="ep-card"><div class="ep-ch"><div><div class="ep-ct">⭐ Weekly Specials</div><div class="ep-cs">Expiring soonest first</div></div></div><table class="ep-tbl"><thead><tr><th>Image</th><th>Destination</th><th>Original Price</th><th>Discount</th><th>Sale Price</th><th>Expires</th><th>Status</th></tr></thead><tbody>`;
  ss.forEach(s=>{
    const dest=dm[s.destination_id];
    const basePrice=s.price!=null?parseFloat(s.price):(dest?parseFloat(dest.price):0);
    const salePrice=basePrice*(1-parseFloat(s.discount)/100);
    const imgSrc=s.image_path||(dest?dest.image:'');
    h+=`<tr>
      <td>${imgSrc?`<img src="${esc(imgSrc)}" class="ep-thumb" onerror="this.style.opacity='.2'">`:''}</td>
      <td><strong>${esc(dest?dest.name:s.destination_id)}</strong></td>
      <td class="ep-price-old">${fmtPrice(basePrice)}</td>
      <td><span class="ep-b bg">${parseFloat(s.discount)}% OFF</span></td>
      <td class="ep-price-new">${fmtPrice(salePrice)}</td>
      <td>${new Date(s.end_date).toLocaleDateString()}</td>
      <td>${expBdg(daysLeft(s.end_date))}</td>
    </tr>`;
  });
  h+=`</tbody></table></div>`;

  /* Pending testimonials */
  const pl=testimonials.filter(t=>t.status==='pending');
  if(pl.length){
    h+=`<div class="ep-card"><div class="ep-ch"><div class="ep-ct">⏳ Pending Testimonials</div></div><div class="ep-cb">`;
    pl.forEach(t=>{
      const av=t.image_path?`<img class="ep-tav" src="${esc(t.image_path)}" alt="">`:`<div class="ep-tavph">${esc(t.full_name.charAt(0))}</div>`;
      h+=`<div class="ep-tc" data-id="${esc(t.id)}">${av}<div class="ep-tb"><div class="ep-tn">${esc(t.full_name)}</div><div class="ep-tl">${esc(t.location)}</div><div class="ep-tm">${esc(t.message)}</div><div class="ep-tacts"><button class="ep-btn ep-suc" data-qa="${esc(t.id)}">✓ Approve</button><button class="ep-btn ep-dan" data-qd="${esc(t.id)}">✗ Deny</button></div></div></div>`;
    });
    h+=`</div></div>`;
  }
  return h;
}

/* Destinations */
function destRow(d){
  return`<tr data-did="${esc(d.id)}">
    <td><img class="ep-thumb" src="${esc(d.image)}" alt="" onerror="this.style.opacity='.2'"></td>
    <td><strong>${esc(d.name)}</strong><br><span style="color:#9ca3af;font-size:11px">${esc(d.location)}</span></td>
    <td><span class="ep-b bb">${esc(d.category)}</span></td>
    <td>${fmtPrice(d.price)}</td>
    <td>⭐ ${parseFloat(d.rating).toFixed(1)}</td>
    <td>${ageBdg(daysAgo(d.created_at))}</td>
    <td style="white-space:nowrap"><button class="ep-btn ep-gho" data-ed="${esc(d.id)}">✏ Edit</button> <button class="ep-btn ep-dan" data-dd="${esc(d.id)}">🗑</button></td>
  </tr>`;
}

function rDest(){
  const cc={};destinations.forEach(d=>{cc[d.category]=(cc[d.category]||0)+1;});
  return`<div class="ep-card">
    <div class="ep-ch"><div><div class="ep-ct">🏷 Categories</div><div class="ep-cs">Add, rename, or remove destination categories</div></div><button class="ep-btn ep-pri" id="ep-cat-tog">+ Add Category</button></div>
    <div class="ep-cb">
      <div class="ep-addbox" id="ep-cat-box">
        <div style="display:flex;gap:10px;align-items:center">
          <input class="ep-inp" id="ep-cat-new" placeholder="New category name" style="max-width:260px">
          <button class="ep-btn ep-pri" id="ep-cat-save">Save</button>
          <button class="ep-btn ep-gho" id="ep-cat-cancel">Cancel</button>
          <span class="ep-smsg" id="ep-cat-msg"></span>
        </div>
      </div>
      <div id="ep-cat-list">${categories.map(c=>{const n=cc[c.name]||0;return`<div class="ep-cat-row" data-cid="${c.id}"><span class="ep-cat-nm">${esc(c.name)}</span><span class="ep-cat-ct">${n} destination${n!==1?'s':''}</span><button class="ep-btn ep-gho" data-ren="${c.id}" data-cv="${esc(c.name)}" style="padding:4px 10px;font-size:11px">Rename</button><button class="ep-btn ep-dan" data-dc="${c.id}" data-dn="${esc(c.name)}" style="padding:4px 10px;font-size:11px"${n>0?' disabled title="In use"':''}>Delete</button></div>`;}).join('')}</div>
    </div>
  </div>
  <div class="ep-card">
    <div class="ep-ch"><div><div class="ep-ct">🗺 All Destinations (${destinations.length})</div></div><button class="ep-btn ep-pri" id="ep-dest-tog">+ Add Destination</button></div>
    <div class="ep-cb">
      <div class="ep-addbox" id="ep-dest-box">
        <div style="font-weight:700;font-size:13px;margin-bottom:14px">New Destination</div>
        <div class="ep-form">
          <div class="ep-fld"><span class="ep-lbl">Name *</span><input class="ep-inp" id="ep-dn-name" placeholder="e.g. Paris"></div>
          <div class="ep-fld"><span class="ep-lbl">Location *</span><input class="ep-inp" id="ep-dn-loc" placeholder="e.g. France"></div>
          <div class="ep-fld"><span class="ep-lbl">Category *</span><select class="ep-sel" id="ep-dn-cat">${catOpts(categories,'')}</select></div>
          <div class="ep-fld"><span class="ep-lbl">Price (USD) *</span><input class="ep-inp" id="ep-dn-price" type="number" placeholder="1299"></div>
          <div class="ep-fld"><span class="ep-lbl">Rating (1–5)</span><input class="ep-inp" id="ep-dn-rating" type="number" step=".1" min="1" max="5" value="4.5"></div>
          <div class="ep-fld ep-full"><span class="ep-lbl">Image *</span>${imgPicker('ep-dn-img','')}</div>
          <div class="ep-fld ep-full"><span class="ep-lbl">Description *</span><textarea class="ep-ta" id="ep-dn-desc"></textarea></div>
          <div class="ep-frow"><span class="ep-smsg" id="ep-dn-msg"></span><button class="ep-btn ep-gho" id="ep-dn-cancel">Cancel</button><button class="ep-btn ep-pri" id="ep-dn-save">Save Destination</button></div>
        </div>
      </div>
      <table class="ep-tbl"><thead><tr><th>Photo</th><th>Name & Location</th><th>Category</th><th>Price</th><th>Rating</th><th>In System</th><th>Actions</th></tr></thead>
      <tbody id="ep-dest-tbody">${destinations.map(destRow).join('')}</tbody></table>
    </div>
  </div>`;
}

/* Specials */
function specImg(s){
  const dm=Object.fromEntries(destinations.map(d=>[d.id,d]));
  const dest=dm[s.destination_id];
  return s.image_path||(dest?dest.image:'')||'';
}
function specRow(s){
  const dm=Object.fromEntries(destinations.map(d=>[d.id,d]));
  const dest=dm[s.destination_id];
  const base=s.price!=null?parseFloat(s.price):(dest?parseFloat(dest.price):0);
  const sale=base*(1-parseFloat(s.discount)/100);
  const img=specImg(s);
  return`<tr data-sid="${esc(s.id)}">
    <td>${img?`<img src="${esc(img)}" class="ep-thumb" onerror="this.style.opacity='.2'">`:''}</td>
    <td><strong>${esc(dest?dest.name:s.destination_id)}</strong></td>
    <td><span class="ep-b bg">${parseFloat(s.discount)}% OFF</span></td>
    <td class="ep-price-old">${fmtPrice(base)}</td>
    <td class="ep-price-new">${fmtPrice(sale)}</td>
    <td>${new Date(s.end_date).toLocaleDateString()}</td>
    <td>${expBdg(daysLeft(s.end_date))}</td>
    <td style="white-space:nowrap"><button class="ep-btn ep-gho" data-es="${esc(s.id)}">✏ Edit</button> <button class="ep-btn ep-dan" data-ds="${esc(s.id)}">🗑</button></td>
  </tr>`;
}

function rSpec(){
  const destOpts=destinations.map(d=>`<option value="${esc(d.id)}">${esc(d.name)}</option>`).join('');
  return`<div class="ep-card">
    <div class="ep-ch"><div><div class="ep-ct">⭐ Weekly Specials (${specials.length})</div></div><button class="ep-btn ep-pri" id="ep-spec-tog">+ Add Special</button></div>
    <div class="ep-cb">
      <div class="ep-addbox" id="ep-spec-box">
        <div style="font-weight:700;font-size:13px;margin-bottom:14px">New Special</div>
        <div class="ep-form">
          <div class="ep-fld"><span class="ep-lbl">Destination *</span><select class="ep-sel" id="ep-sn-dest">${destOpts}</select></div>
          <div class="ep-fld"><span class="ep-lbl">Original Price (USD) *</span><input class="ep-inp" id="ep-sn-price" type="number" placeholder="1299" title="Base price before discount"></div>
          <div class="ep-fld"><span class="ep-lbl">Discount % *</span><input class="ep-inp" id="ep-sn-disc" type="number" min="1" max="99" placeholder="25"></div>
          <div class="ep-fld"><span class="ep-lbl">End Date *</span><input class="ep-inp" id="ep-sn-end" type="date"></div>
          <div class="ep-fld ep-full"><span class="ep-lbl">Special Image (optional — defaults to destination photo)</span>${imgPicker('ep-sn-img','')}</div>
          <div class="ep-fld ep-full"><span class="ep-lbl">Highlights (one per line)</span><textarea class="ep-ta" id="ep-sn-hls" placeholder="Free spa treatment&#10;Complimentary airport transfer"></textarea></div>
          <div class="ep-frow"><span class="ep-smsg" id="ep-sn-msg"></span><button class="ep-btn ep-gho" id="ep-sn-cancel">Cancel</button><button class="ep-btn ep-pri" id="ep-sn-save">Save Special</button></div>
        </div>
      </div>
      <table class="ep-tbl"><thead><tr><th>Image</th><th>Destination</th><th>Discount</th><th>Original Price</th><th>Sale Price</th><th>End Date</th><th>Status</th><th>Actions</th></tr></thead>
      <tbody id="ep-spec-tbody">${specials.map(specRow).join('')}</tbody></table>
    </div>
  </div>`;
}

/* Testimonials */
function rTest(){
  const cn={pending:0,approved:0,denied:0};testimonials.forEach(t=>cn[t.status]++);
  const list=tFilter==='all'?testimonials:testimonials.filter(t=>t.status===tFilter);
  let h=`<div class="ep-ftabs">
    <button class="ep-ft ${tFilter==='pending'?'active':''}"  data-tf="pending">⏳ Pending (${cn.pending})</button>
    <button class="ep-ft ${tFilter==='approved'?'active':''}" data-tf="approved">✅ Approved (${cn.approved})</button>
    <button class="ep-ft ${tFilter==='denied'?'active':''}"   data-tf="denied">❌ Denied (${cn.denied})</button>
    <button class="ep-ft ${tFilter==='all'?'active':''}"      data-tf="all">All (${testimonials.length})</button>
  </div>`;
  if(!list.length)return h+`<div class="ep-empty">💬 No testimonials here.</div>`;
  list.forEach(t=>{
    const av=t.image_path?`<img class="ep-tav" src="${esc(t.image_path)}" alt="">`:`<div class="ep-tavph">${esc(t.full_name.charAt(0))}</div>`;
    const sb=`<span class="ep-b ${t.status==='approved'?'bg':t.status==='denied'?'br':'by'}">${t.status}</span>`;
    h+=`<div class="ep-tc" data-tid="${esc(t.id)}">${av}<div class="ep-tb">
      <div class="ep-tn">${esc(t.full_name)} ${sb}</div><div class="ep-tl">${esc(t.location)}</div>
      <div class="ep-tm">${esc(t.message)}</div>
      <textarea class="ep-te">${esc(t.message)}</textarea>
      <div class="ep-tacts">
        ${t.status!=='approved'?`<button class="ep-btn ep-suc" data-ta="approve" data-tid="${esc(t.id)}">✓ Approve</button>`:''}
        ${t.status!=='denied'?`<button class="ep-btn ep-dan" data-ta="deny" data-tid="${esc(t.id)}">✗ Deny</button>`:''}
        <button class="ep-btn ep-gho" data-ta="save" data-tid="${esc(t.id)}">💾 Save Edit</button>
        <button class="ep-btn ep-dan" data-ta="delete" data-tid="${esc(t.id)}">🗑 Delete</button>
      </div></div></div>`;
  });
  return h;
}

/* Render */
function render(){
  const body=document.getElementById('ep-body');if(!body)return;
  switch(activeTab){
    case'dashboard':   body.innerHTML=rDash(); wireDash(); break;
    case'destinations':body.innerHTML=rDest(); wireDest(); break;
    case'specials':    body.innerHTML=rSpec(); wireSpec(); break;
    case'testimonials':body.innerHTML=rTest(); wireTest(); break;
  }
  const pb=document.getElementById('ep-pb');
  if(pb){const n=testimonials.filter(t=>t.status==='pending').length;pb.textContent=n||'';pb.style.display=n?'':'none';}
}

/* Wire: Dashboard */
function wireDash(){
  document.querySelectorAll('[data-qa]').forEach(b=>b.onclick=async()=>{await api(`/testimonials/${b.dataset.qa}`,{method:'PUT',body:JSON.stringify({status:'approved'})});await loadAll();render();});
  document.querySelectorAll('[data-qd]').forEach(b=>b.onclick=async()=>{await api(`/testimonials/${b.dataset.qd}`,{method:'PUT',body:JSON.stringify({status:'denied'})});await loadAll();render();});
}

/* Wire: Destinations */
function wireDest(){
  /* Categories */
  const ct=document.getElementById('ep-cat-tog'),cb=document.getElementById('ep-cat-box');
  if(ct)ct.onclick=()=>cb.classList.toggle('open');
  const cc=document.getElementById('ep-cat-cancel');if(cc)cc.onclick=()=>cb.classList.remove('open');
  const cs=document.getElementById('ep-cat-save');
  if(cs)cs.onclick=async()=>{
    const m=document.getElementById('ep-cat-msg'),nm=document.getElementById('ep-cat-new').value.trim();
    if(!nm){m.textContent='Name required';m.className='ep-smsg err';return;}
    try{await api('/categories',{method:'POST',body:JSON.stringify({name:nm})});m.textContent='Added!';m.className='ep-smsg ok';await loadAll();activeTab='destinations';render();}
    catch(e){m.textContent=e.message;m.className='ep-smsg err';}
  };
  document.querySelectorAll('[data-ren]').forEach(b=>b.onclick=()=>{
    const id=b.dataset.ren,cur=b.dataset.cv,row=b.closest('.ep-cat-row');
    row.innerHTML=`<input class="ep-cat-ei" id="ep-ren-${id}" value="${esc(cur)}"><button class="ep-btn ep-pri" data-rs="${id}" style="padding:5px 10px;font-size:11px">Save</button><button class="ep-btn ep-gho" data-rc style="padding:5px 10px;font-size:11px">Cancel</button><span class="ep-smsg" id="ep-rm-${id}"></span>`;
    row.querySelector('[data-rc]').onclick=()=>{activeTab='destinations';render();};
    row.querySelector(`[data-rs="${id}"]`).onclick=async()=>{
      const nm=document.getElementById(`ep-ren-${id}`).value.trim(),m=document.getElementById(`ep-rm-${id}`);
      if(!nm){m.textContent='Required';m.className='ep-smsg err';return;}
      try{await api(`/categories/${id}`,{method:'PUT',body:JSON.stringify({name:nm})});await loadAll();activeTab='destinations';render();}
      catch(e){m.textContent=e.message;m.className='ep-smsg err';}
    };
  });
  document.querySelectorAll('[data-dc]').forEach(b=>b.onclick=async()=>{
    if(!confirm(`Delete category "${b.dataset.dn}"?`))return;
    try{await api(`/categories/${b.dataset.dc}`,{method:'DELETE'});await loadAll();activeTab='destinations';render();}catch(e){alert(e.message);}
  });

  /* Destination add */
  const dt=document.getElementById('ep-dest-tog'),db=document.getElementById('ep-dest-box');
  if(dt)dt.onclick=()=>db.classList.toggle('open');
  const dn=document.getElementById('ep-dn-cancel');if(dn)dn.onclick=()=>db.classList.remove('open');
  const ds=document.getElementById('ep-dn-save');
  if(ds)ds.onclick=async()=>{
    const m=document.getElementById('ep-dn-msg');
    try{
      const img=await getImg('ep-dn-img','');
      await api('/destinations',{method:'POST',body:JSON.stringify({
        name:document.getElementById('ep-dn-name').value.trim(),
        location:document.getElementById('ep-dn-loc').value.trim(),
        category:document.getElementById('ep-dn-cat').value,
        price:document.getElementById('ep-dn-price').value,
        rating:document.getElementById('ep-dn-rating').value||'4.5',
        image:img,
        description:document.getElementById('ep-dn-desc').value.trim()
      })});
      m.textContent='Saved!';m.className='ep-smsg ok';await loadAll();activeTab='destinations';render();
    }catch(e){m.textContent=e.message;m.className='ep-smsg err';}
  };

  /* Destination edit */
  document.querySelectorAll('[data-ed]').forEach(b=>b.onclick=()=>{
    const id=b.dataset.ed,d=destinations.find(x=>x.id==id);if(!d)return;
    const row=document.querySelector(`tr[data-did="${id}"]`);
    row.innerHTML=`<td colspan="7"><div class="ep-inline ep-form">
      <div class="ep-fld"><span class="ep-lbl">Name</span><input class="ep-inp" id="ei-n-${id}" value="${esc(d.name)}"></div>
      <div class="ep-fld"><span class="ep-lbl">Location</span><input class="ep-inp" id="ei-l-${id}" value="${esc(d.location)}"></div>
      <div class="ep-fld"><span class="ep-lbl">Category</span><select class="ep-sel" id="ei-c-${id}">${catOpts(categories,d.category)}</select></div>
      <div class="ep-fld"><span class="ep-lbl">Price</span><input class="ep-inp" type="number" id="ei-p-${id}" value="${esc(d.price)}"></div>
      <div class="ep-fld"><span class="ep-lbl">Rating</span><input class="ep-inp" type="number" step=".1" id="ei-r-${id}" value="${esc(d.rating)}"></div>
      <div class="ep-fld ep-full"><span class="ep-lbl">Image (upload new to replace)</span>${imgPicker('ei-i-'+id,d.image)}</div>
      <div class="ep-fld ep-full"><span class="ep-lbl">Description</span><textarea class="ep-ta" id="ei-d-${id}">${esc(d.description)}</textarea></div>
      <div class="ep-frow">
        <button class="ep-btn ep-gho" data-ec="${id}">Cancel</button>
        <button class="ep-btn ep-pri" data-es="${id}">Save Changes</button>
      </div>
    </div></td>`;
    row.querySelector(`[data-ec="${id}"]`).onclick=()=>{row.outerHTML=destRow(d);wireDest();};
    row.querySelector(`[data-es="${id}"]`).onclick=async()=>{
      try{
        const img=await getImg('ei-i-'+id,d.image);
        await api(`/destinations/${id}`,{method:'PUT',body:JSON.stringify({
          name:document.getElementById(`ei-n-${id}`).value,
          location:document.getElementById(`ei-l-${id}`).value,
          category:document.getElementById(`ei-c-${id}`).value,
          price:document.getElementById(`ei-p-${id}`).value,
          rating:document.getElementById(`ei-r-${id}`).value,
          image:img,
          description:document.getElementById(`ei-d-${id}`).value
        })});
        await loadAll();activeTab='destinations';render();
      }catch(e){alert(e.message);}
    };
  });

  /* Destination delete */
  document.querySelectorAll('[data-dd]').forEach(b=>b.onclick=async()=>{
    if(!confirm('Delete this destination? This cannot be undone.'))return;
    try{await api(`/destinations/${b.dataset.dd}`,{method:'DELETE'});await loadAll();activeTab='destinations';render();}catch(e){alert(e.message);}
  });
}

/* Wire: Specials */
function wireSpec(){
  const st=document.getElementById('ep-spec-tog'),sb=document.getElementById('ep-spec-box');
  if(st)st.onclick=()=>sb.classList.toggle('open');
  const sc=document.getElementById('ep-sn-cancel');if(sc)sc.onclick=()=>sb.classList.remove('open');
  const ss=document.getElementById('ep-sn-save');
  if(ss)ss.onclick=async()=>{
    const m=document.getElementById('ep-sn-msg');
    try{
      const img=await getImg('ep-sn-img',null);
      const hls=document.getElementById('ep-sn-hls').value.split('\n').map(l=>l.trim()).filter(Boolean);
      await api('/specials',{method:'POST',body:JSON.stringify({
        destination_id:document.getElementById('ep-sn-dest').value,
        price:document.getElementById('ep-sn-price').value,
        discount:document.getElementById('ep-sn-disc').value,
        end_date:document.getElementById('ep-sn-end').value,
        image_path:img,
        highlights:hls
      })});
      m.textContent='Saved!';m.className='ep-smsg ok';await loadAll();activeTab='specials';render();
    }catch(e){m.textContent=e.message;m.className='ep-smsg err';}
  };

  /* Specials edit */
  document.querySelectorAll('[data-es]').forEach(b=>b.onclick=()=>{
    const id=b.dataset.es,s=specials.find(x=>x.id==id);if(!s)return;
    const dm=Object.fromEntries(destinations.map(d=>[d.id,d]));
    const dest=dm[s.destination_id];
    const hls=Array.isArray(s.highlights)?s.highlights.join('\n'):'';
    const curImg=specImg(s);
    const row=document.querySelector(`tr[data-sid="${id}"]`);
    row.innerHTML=`<td colspan="8"><div class="ep-inline ep-form">
      <div class="ep-fld"><span class="ep-lbl">Original Price</span><input class="ep-inp" type="number" id="si-p-${id}" value="${esc(s.price!=null?s.price:(dest?dest.price:''))}"></div>
      <div class="ep-fld"><span class="ep-lbl">Discount %</span><input class="ep-inp" type="number" id="si-d-${id}" value="${esc(s.discount)}"></div>
      <div class="ep-fld"><span class="ep-lbl">End Date</span><input class="ep-inp" type="date" id="si-e-${id}" value="${esc(s.end_date)}"></div>
      <div class="ep-fld ep-full"><span class="ep-lbl">Image (upload to replace; leave blank to use destination photo)</span>${imgPicker('si-i-'+id,curImg)}</div>
      <div class="ep-fld ep-full"><span class="ep-lbl">Highlights (one per line)</span><textarea class="ep-ta" id="si-h-${id}">${esc(hls)}</textarea></div>
      <div class="ep-frow">
        <button class="ep-btn ep-gho" data-sc="${id}">Cancel</button>
        <button class="ep-btn ep-pri" data-sv="${id}">Save</button>
      </div>
    </div></td>`;
    row.querySelector(`[data-sc="${id}"]`).onclick=()=>{row.outerHTML=specRow(s);wireSpec();};
    row.querySelector(`[data-sv="${id}"]`).onclick=async()=>{
      try{
        const newImg=await getImg('si-i-'+id,s.image_path||null);
        const hls2=document.getElementById(`si-h-${id}`).value.split('\n').map(l=>l.trim()).filter(Boolean);
        await api(`/specials/${id}`,{method:'PUT',body:JSON.stringify({
          price:document.getElementById(`si-p-${id}`).value,
          discount:document.getElementById(`si-d-${id}`).value,
          end_date:document.getElementById(`si-e-${id}`).value,
          image_path:newImg,
          highlights:hls2
        })});
        await loadAll();activeTab='specials';render();
      }catch(e){alert(e.message);}
    };
  });

  /* Specials delete */
  document.querySelectorAll('[data-ds]').forEach(b=>b.onclick=async()=>{
    if(!confirm('Delete this special?'))return;
    try{await api(`/specials/${b.dataset.ds}`,{method:'DELETE'});await loadAll();activeTab='specials';render();}catch(e){alert(e.message);}
  });
}

/* Wire: Testimonials */
function wireTest(){
  document.querySelectorAll('[data-tf]').forEach(b=>b.onclick=()=>{tFilter=b.dataset.tf;render();});
  document.querySelectorAll('[data-ta]').forEach(b=>b.onclick=async()=>{
    const id=b.dataset.tid,action=b.dataset.ta;
    const card=document.querySelector(`.ep-tc[data-tid="${id}"]`);
    try{
      if(action==='approve')await api(`/testimonials/${id}`,{method:'PUT',body:JSON.stringify({status:'approved'})});
      else if(action==='deny')await api(`/testimonials/${id}`,{method:'PUT',body:JSON.stringify({status:'denied'})});
      else if(action==='save'){const ta=card.querySelector('.ep-te');await api(`/testimonials/${id}`,{method:'PUT',body:JSON.stringify({message:ta.value})});}
      else if(action==='delete'){if(!confirm('Delete?'))return;await api(`/testimonials/${id}`,{method:'DELETE'});}
      await loadAll();render();
    }catch(e){alert(e.message);}
  });
}

/* Init */
let injected=false;
function tryInject(){
  if(injected)return;
  if(!window.location.pathname.startsWith('/admin/dashboard'))return;
  if(!localStorage.getItem('isAdminAuthenticated'))return;
  const root=document.getElementById('root');
  if(!root||!root.children.length)return;
  injected=true;obs.disconnect();
  Array.from(root.children).forEach(c=>c.style.display='none');
  const portal=buildShell();root.insertBefore(portal,root.firstChild);
  loadAll().then(render);
}
const obs=new MutationObserver(tryInject);
obs.observe(document.body,{childList:true,subtree:true});
tryInject();
})();
