// ── Photos page ────────────────────────────────────────────────────────────────

let _nextUrl    = null;   // pagination cursor
let _allPhotos  = [];     // accumulated list
let _lbGpId     = null;   // currently open in lightbox

const lightboxModal = new bootstrap.Modal('#lightboxModal');
const uploadModal   = new bootstrap.Modal('#uploadModal');

// esc, showToast, fDist, getDistUnit, getVelUnit → utils.js

// ── Load & render photos ───────────────────────────────────────────────────────

async function loadPhotos(reset = false) {
  if (reset) {
    _allPhotos = [];
    _nextUrl   = null;
    document.getElementById('photoGrid').innerHTML = '';
  }

  const spinner = document.getElementById('gridSpinner');
  const loadBtn = document.getElementById('loadMoreBtn');
  spinner.classList.remove('d-none');
  loadBtn.style.display = 'none';

  try {
    const filter = document.getElementById('filterMeasured').value;
    const url = _nextUrl || buildUrl(filter);
    const data = await apiGet(url);
    const items  = asList(data);
    _nextUrl = data.next ? new URL(data.next).pathname + new URL(data.next).search : null;

    _allPhotos = [..._allPhotos, ...items];
    renderCards(items);
    updateCount();

    loadBtn.style.display = _nextUrl ? '' : 'none';
  } catch(e) {
    showToast('Failed to load photos.', 'danger');
  } finally {
    spinner.classList.add('d-none');
  }
}

function buildUrl(filter) {
  let url = '/photos/group-photos/?page_size=24';
  // filtering by measured / unmeasured is done client-side after load
  return url;
}

function updateCount() {
  const filter = document.getElementById('filterMeasured').value;
  let shown = _allPhotos;
  if (filter === 'measured')   shown = shown.filter(p => p.analysis?.group_size_mm != null);
  if (filter === 'unmeasured') shown = shown.filter(p => !p.analysis?.group_size_mm);
  document.getElementById('photoCount').textContent = `${shown.length} photo${shown.length !== 1 ? 's' : ''}`;
  document.getElementById('emptyMsg').classList.toggle('d-none', shown.length > 0);
}

function renderCards(items) {
  const filter = document.getElementById('filterMeasured').value;
  const grid = document.getElementById('photoGrid');

  const filtered = filter === 'measured'   ? items.filter(p => p.analysis?.group_size_mm != null)
                 : filter === 'unmeasured' ? items.filter(p => !p.analysis?.group_size_mm)
                 : items;

  if (!filtered.length) return;

  filtered.forEach(gp => {
    const col = document.createElement('div');
    col.className = 'col-6 col-sm-4 col-md-3 col-lg-2';
    col.dataset.gpId = gp.id;

    const an    = gp.analysis;
    const sg    = gp.shot_group_detail;
    const distM = sg?.distance_m ? parseFloat(sg.distance_m) : null;
    const esMm  = an?.group_size_mm != null ? parseFloat(an.group_size_mm) : null;
    const esMoa = an?.group_size_moa;

    const esBadge = esMm != null
      ? `<span class="badge bg-success photo-card badge-es">${fDist(esMm, esMoa, distM)}</span>`
      : '';
    const caption = gp.caption || (sg ? sg.label : '');
    const poiCount = (gp.points_of_impact || []).length;

    col.innerHTML = `
      <div class="photo-card">
        <img src="/api/photos/${gp.photo.id}/data/"
             alt="${esc(caption)}"
             onclick="openLightbox(${gp.id})">
        <div class="overlay"></div>
        ${esBadge}
        <div class="actions">
          <a href="/group-size.html?gp=${gp.id}" class="btn btn-sm btn-light btn-icon" title="Measure">
            <i class="bi bi-crosshair2"></i>
          </a>
          <button class="btn btn-sm btn-light btn-icon" title="Compute group size"
                  onclick="computeGroupSize(event, ${gp.id}, ${gp.id})">
            <i class="bi bi-calculator"></i>
          </button>
          <button class="btn btn-sm btn-light btn-icon text-danger" title="Delete"
                  onclick="deletePhoto(event, ${gp.id})">
            <i class="bi bi-trash"></i>
          </button>
        </div>
        <div class="footer">
          <div class="text-truncate" style="max-width:100%">${esc(caption)}</div>
          ${sg ? `<div class="opacity-75">${esc(sg.label)}${distM ? ` · ${distM} m` : ''}</div>` : ''}
          ${poiCount ? `<div class="opacity-75">${poiCount} POI${poiCount > 1 ? 's' : ''}</div>` : ''}
        </div>
      </div>`;
    grid.appendChild(col);
  });
}

// ── Lightbox ───────────────────────────────────────────────────────────────────

function openLightbox(gpId) {
  const gp = _allPhotos.find(p => p.id === gpId);
  if (!gp) return;
  _lbGpId = gpId;

  const sg    = gp.shot_group_detail;
  const an    = gp.analysis;
  const distM = sg?.distance_m ? parseFloat(sg.distance_m) : null;
  const caption = gp.caption || (sg ? sg.label : '');

  document.getElementById('lbTitle').textContent =
    caption || `Photo #${gp.id}`;

  const badge = document.getElementById('lbBadge');
  if (sg) { badge.textContent = sg.label + (distM ? ` · ${distM} m` : ''); badge.classList.remove('d-none'); }
  else badge.classList.add('d-none');

  renderLbStats(gp);
  applyDistUnitButtons(document.getElementById('lightboxModal'));
  renderPublicToggle(gp.is_public, {
    btnId: 'lbTogglePublicBtn', iconId: 'lbTogglePublicIcon',
    labelId: 'lbTogglePublicLabel', privateClass: 'btn-outline-light',
  });

  document.getElementById('lbMeasureBtn').href = `/group-size.html?gp=${gp.id}`;
  document.getElementById('lbOpenBtn').href    = `/api/photos/${gp.photo.id}/data/`;
  document.getElementById('lbImg').src         = `/api/photos/${gp.photo.id}/data/`;

  lightboxModal.show();
}

function renderLbStats(gp) {
  const an    = gp.analysis;
  const sg    = gp.shot_group_detail;
  const distM = sg?.distance_m ? parseFloat(sg.distance_m) : null;
  const parts = [];

  const poiCount = (gp.points_of_impact || []).length;
  if (poiCount) parts.push(`<span><span class="opacity-50">POIs:</span> <strong class="text-white">${poiCount}</strong></span>`);

  if (an) {
    if (an.group_size_mm != null)
      parts.push(`<span><span class="opacity-50">Group ES:</span> <strong class="text-white">${fDist(an.group_size_mm, an.group_size_moa, distM)}</strong></span>`);
    if (an.mean_radius_mm != null)
      parts.push(`<span><span class="opacity-50">Mean radius:</span> <strong class="text-white">${fDist(an.mean_radius_mm, an.mean_radius_moa, distM)}</strong></span>`);
    const wx = an.windage_offset_mm  != null ? parseFloat(an.windage_offset_mm)  : null;
    const wy = an.elevation_offset_mm != null ? parseFloat(an.elevation_offset_mm) : null;
    if (wx != null && wy != null && (Math.abs(wx) > 0.5 || Math.abs(wy) > 0.5)) {
      parts.push(`<span><span class="opacity-50">Offset:</span> <strong class="text-white">${fDist(Math.abs(wx), an.windage_offset_moa, distM)} ${wx>0?'R':'L'} / ${fDist(Math.abs(wy), an.elevation_offset_moa, distM)} ${wy>0?'H':'Low'}</strong></span>`);
    }
  }

  document.getElementById('lbStats').innerHTML =
    parts.length ? parts.join('') : '<span class="opacity-50">Not yet measured — click Measure or Compute.</span>';
}

// ── Compute group size ─────────────────────────────────────────────────────────

async function computeGroupSize(e, gpId, colGpId) {
  e.stopPropagation();
  const gp = _allPhotos.find(p => p.id === gpId);
  if (!gp || (gp.points_of_impact || []).length < 2) {
    showToast('Need ≥ 2 annotated POIs to compute. Use "Measure" first.', 'warning');
    return;
  }
  try {
    const result = await apiPost(`/photos/group-photos/${gpId}/compute-group-size/`, {});
    // Update cache
    const idx = _allPhotos.findIndex(p => p.id === gpId);
    if (idx !== -1) _allPhotos[idx] = { ..._allPhotos[idx], analysis: result.analysis ?? result };
    // Refresh card
    const old = document.querySelector(`[data-gp-id="${gpId}"]`);
    if (old) { old.remove(); renderCards([_allPhotos[idx]]); }
    // Refresh lightbox if open on this photo
    if (_lbGpId === gpId) renderLbStats(_allPhotos[idx]);
    showToast('Group size computed.');
  } catch(err) {
    showToast('Compute failed: ' + (err.message || 'unknown error'), 'danger');
  }
}

// ── Delete ─────────────────────────────────────────────────────────────────────

async function deletePhoto(e, gpId) {
  e.stopPropagation();
  if (!confirm('Delete this photo?')) return;
  try {
    await apiDelete(`/photos/group-photos/${gpId}/`);
    const col = document.querySelector(`[data-gp-id="${gpId}"]`);
    col?.closest('.col-6, .col-sm-4, .col-md-3, .col-lg-2')?.remove();
    _allPhotos = _allPhotos.filter(p => p.id !== gpId);
    updateCount();
    showToast('Photo deleted.');
    if (_lbGpId === gpId) lightboxModal.hide();
  } catch(err) {
    showToast('Delete failed.', 'danger');
  }
}

// ── Compute from lightbox ──────────────────────────────────────────────────────

document.getElementById('lbComputeBtn').addEventListener('click', () => {
  if (_lbGpId != null) computeGroupSize({ stopPropagation: ()=>{} }, _lbGpId, _lbGpId);
});

// ── Public toggle from lightbox ────────────────────────────────────────────────

document.getElementById('lbTogglePublicBtn').addEventListener('click', async () => {
  if (_lbGpId == null) return;
  const idx = _allPhotos.findIndex(p => p.id === _lbGpId);
  if (idx === -1) return;
  const gp = _allPhotos[idx];
  const newVal = !gp.is_public;
  try {
    await apiPatch(`/photos/group-photos/${gp.id}/`, { is_public: newVal });
    _allPhotos[idx] = { ...gp, is_public: newVal };
    renderPublicToggle(newVal, {
      btnId: 'lbTogglePublicBtn', iconId: 'lbTogglePublicIcon',
      labelId: 'lbTogglePublicLabel', privateClass: 'btn-outline-light',
    });
    showToast(newVal ? 'Photo is now public.' : 'Photo is now private.');
  } catch(e) {
    showToast('Failed to update visibility.', 'danger');
  }
});

// ── Unit switch inside lightbox ────────────────────────────────────────────────

document.getElementById('lightboxModal').addEventListener('click', e => {
  const btn = e.target.closest('[data-dist-unit]');
  if (!btn) return;
  setDistUnit(btn.dataset.distUnit);
  applyDistUnitButtons(document.getElementById('lightboxModal'));
  if (_lbGpId != null) {
    const gp = _allPhotos.find(p => p.id === _lbGpId);
    if (gp) renderLbStats(gp);
  }
});

// ── Upload ─────────────────────────────────────────────────────────────────────

document.getElementById('uploadBtn').addEventListener('click', () => {
  document.getElementById('upFile').value     = '';
  document.getElementById('upCaption').value  = '';
  document.getElementById('upAlert').classList.add('d-none');
  uploadModal.show();
});

document.getElementById('upSubmitBtn').addEventListener('click', async () => {
  const alertEl   = document.getElementById('upAlert');
  const spinner   = document.getElementById('upSpinner');
  const submitBtn = document.getElementById('upSubmitBtn');
  alertEl.classList.add('d-none');

  const file = document.getElementById('upFile').files[0];
  if (!file) {
    alertEl.textContent = 'Please select an image file.';
    alertEl.classList.remove('d-none');
    return;
  }

  submitBtn.disabled = true;
  spinner.classList.remove('d-none');
  try {
    const formData = new FormData();
    formData.append('file', file);
    const photo = await apiFetch('/photos/upload/', { method: 'POST', body: formData })
      .then(async r => {
        if (!r.ok) { const e = await r.json().catch(() => ({})); throw Object.assign(new Error('Upload failed'), { data: e }); }
        return r.json();
      });

    const caption = document.getElementById('upCaption').value.trim();
    const gp = await apiPost('/photos/group-photos/', {
      photo_id: photo.id,
      ...(caption ? { caption } : {}),
    });

    _allPhotos.unshift(gp);
    renderCards([gp]);
    // Move the new card to front
    const grid = document.getElementById('photoGrid');
    const newCol = grid.querySelector(`[data-gp-id="${gp.id}"]`)?.closest('[class^="col"]');
    if (newCol) grid.prepend(newCol);

    updateCount();
    uploadModal.hide();
    showToast('Photo uploaded.');
  } catch(err) {
    alertEl.textContent = (err.data && JSON.stringify(err.data)) || 'Upload failed.';
    alertEl.classList.remove('d-none');
  } finally {
    submitBtn.disabled = false;
    spinner.classList.add('d-none');
  }
});

// ── Filter ─────────────────────────────────────────────────────────────────────

document.getElementById('filterMeasured').addEventListener('change', () => {
  // Re-render current data without re-fetching
  document.getElementById('photoGrid').innerHTML = '';
  renderCards(_allPhotos);
  updateCount();
});

// ── Load more ──────────────────────────────────────────────────────────────────

document.getElementById('loadMoreBtn').addEventListener('click', () => loadPhotos(false));

// ── Boot ───────────────────────────────────────────────────────────────────────

loadPhotos(true);
