// ── Chronograph Analyser page logic ───────────────────────────────────────────

let sessions = [];
let currentSessionId = null;
let _photoTargetGroupId = null;  // group id for current photo upload modal

// showToast, renderPublicToggle → utils.js

// ── Sessions list ─────────────────────────────────────────────────────────────

async function loadSessions() {
  try {
    sessions = await apiGetAll('/tools/chronograph/');
    renderSessionsList();
  } catch(e) {
    document.getElementById('sessionsSpinner').innerHTML =
      '<p class="text-danger small">Failed to load sessions.</p>';
  }
}

function renderSessionsList() {
  document.getElementById('sessionsSpinner').classList.add('d-none');
  const list = document.getElementById('sessionsList');
  const empty = document.getElementById('sessionsEmpty');

  if (!sessions.length) {
    empty.classList.remove('d-none');
    list.innerHTML = '';
    return;
  }
  empty.classList.add('d-none');

  list.innerHTML = sessions.map(s => `
    <div class="session-item mb-1 ${s.id === currentSessionId ? 'active' : ''}"
         onclick="selectSession(${s.id})">
      <div class="fw-semibold small">${s.name}</div>
      <div class="text-muted small">${s.date || ''}</div>
    </div>
  `).join('');
}

// ── Select & display a session ────────────────────────────────────────────────

async function selectSession(id) {
  currentSessionId = id;
  renderSessionsList();

  document.getElementById('noSessionMsg').classList.add('d-none');
  document.getElementById('analysisContent').classList.remove('d-none');
  document.getElementById('chartsSpinner').classList.remove('d-none');
  document.getElementById('chartsContent').classList.add('d-none');

  const session = sessions.find(s => s.id === id);
  document.getElementById('sessionTitle').textContent = session?.name || 'Session';
  document.getElementById('sessionDate').textContent  = session?.date || '';
  renderPublicToggle(session?.is_public || false);

  try {
    // Fetch detail (includes groups + per-group stats via serializer)
    const detail = await apiGet(`/tools/chronograph/${id}/`);
    // Fetch chart images
    const charts = await apiGet(`/tools/chronograph/${id}/charts/`);

    renderAnalysis(detail, charts);
  } catch(e) {
    document.getElementById('chartsSpinner').innerHTML =
      '<p class="text-danger text-center py-4">Failed to load analysis.</p>';
  }
}

function fmtFps(v) {
  return v != null ? `${Number(v).toFixed(1)} fps` : '—';
}

function renderAnalysis(detail, charts) {
  document.getElementById('chartsSpinner').classList.add('d-none');
  document.getElementById('chartsContent').classList.remove('d-none');

  // Overall stats from all shots
  const allShots = (detail.shot_groups || []).flatMap(g => g.shots || []);
  const speeds   = allShots.map(s => parseFloat(s.velocity_fps)).filter(v => !isNaN(v));
  const overallStats = computeStats(speeds);

  document.getElementById('overallStatsWrap').innerHTML = renderStatsTable(overallStats);

  // Overview chart
  const overviewImg = document.getElementById('overviewChart');
  if (charts.overview) {
    overviewImg.src = `data:image/png;base64,${charts.overview}`;
    overviewImg.style.display = '';
  } else {
    overviewImg.style.display = 'none';
  }

  // Per-group sections
  const groups      = detail.shot_groups || [];
  const groupCharts = charts.groups || [];
  const groupHtml = groups.map((g, i) => {
    const gSpeeds = (g.shots || []).map(s => parseFloat(s.velocity_fps)).filter(v => !isNaN(v));
    const gStats  = computeStats(gSpeeds);
    const chartB64 = groupCharts[i];
    return `
      <div class="card border-0 shadow-sm mb-3" id="group-card-${g.id}">
        <div class="card-body">
          <div class="d-flex justify-content-between align-items-center mb-3 flex-wrap gap-2">
            <h6 class="fw-semibold mb-0">
              <i class="bi bi-collection me-1"></i>
              ${g.label || 'Group ' + (i+1)}
              <span class="text-muted fw-normal ms-2 small">${g.distance_m ? g.distance_m + ' m' : ''}</span>
            </h6>
            <span class="badge bg-secondary">${gSpeeds.length} shots</span>
          </div>
          <div class="row g-3">
            <div class="col-md-5">
              ${renderStatsTable(gStats)}
            </div>
            <div class="col-md-7">
              ${chartB64
                ? `<img src="data:image/png;base64,${chartB64}" class="group-chart w-100" alt="Group chart">`
                : '<p class="text-muted small">No chart available.</p>'}
            </div>
          </div>

          <!-- Photos section -->
          <div class="mt-3 pt-2 border-top">
            <div class="d-flex align-items-center mb-2">
              <span class="small fw-semibold text-muted"><i class="bi bi-images me-1"></i>Target photo</span>
            </div>
            <div id="photos-${g.id}">
              <span class="text-muted small">Loading…</span>
            </div>
          </div>

        </div>
      </div>`;
  }).join('');

  document.getElementById('groupSections').innerHTML = groupHtml ||
    '<p class="text-muted">No shot groups in this session.</p>';

  // Load photos for each group asynchronously
  groups.forEach(g => loadGroupPhotos(g.id));
}

function computeStats(speeds) {
  if (!speeds.length) return null;
  const n    = speeds.length;
  const avg  = speeds.reduce((a,b) => a+b, 0) / n;
  const min  = Math.min(...speeds);
  const max  = Math.max(...speeds);
  const es   = max - min;
  const sd   = n > 1
    ? Math.sqrt(speeds.reduce((s,v) => s + (v-avg)**2, 0) / (n-1))
    : null;
  return { n, avg, min, max, es, sd };
}

function renderStatsTable(stats) {
  if (!stats) return '<p class="text-muted small">No data.</p>';
  const sdText = stats.sd != null ? `${stats.sd.toFixed(1)} fps` : '—';
  return `
    <table class="table table-sm stat-table mb-0">
      <tbody>
        <tr><td>Shots</td><td>${stats.n}</td></tr>
        <tr><td>Average</td><td>${stats.avg.toFixed(1)} fps</td></tr>
        <tr><td>Min</td><td>${stats.min.toFixed(1)} fps</td></tr>
        <tr><td>Max</td><td>${stats.max.toFixed(1)} fps</td></tr>
        <tr><td>Extreme spread (ES)</td><td>${stats.es.toFixed(1)} fps</td></tr>
        <tr><td>Std deviation (SD)</td><td>${sdText}</td></tr>
      </tbody>
    </table>`;
}

// ── Public toggle (renderPublicToggle → utils.js) ────────────────────────────

document.getElementById('togglePublicBtn').addEventListener('click', async () => {
  if (!currentSessionId) return;
  const session = sessions.find(s => s.id === currentSessionId);
  if (!session) return;
  const newVal = !session.is_public;
  try {
    await apiPatch(`/tools/chronograph/${currentSessionId}/`, { is_public: newVal });
    session.is_public = newVal;
    renderPublicToggle(newVal);
    showToast(newVal ? 'Analysis is now public.' : 'Analysis is now private.');
  } catch(e) {
    showToast('Failed to update visibility.', 'danger');
  }
});

// ── Delete session ────────────────────────────────────────────────────────────

document.getElementById('deleteSessionBtn').addEventListener('click', async () => {
  if (!currentSessionId) return;
  if (!confirm('Delete this session and all its data?')) return;
  try {
    await apiDelete(`/tools/chronograph/${currentSessionId}/`);
    sessions = sessions.filter(s => s.id !== currentSessionId);
    currentSessionId = null;
    document.getElementById('noSessionMsg').classList.remove('d-none');
    document.getElementById('analysisContent').classList.add('d-none');
    renderSessionsList();
    showToast('Session deleted.');
  } catch(e) {
    showToast('Failed to delete session.', 'danger');
  }
});

// ── Download PDF ──────────────────────────────────────────────────────────────

document.getElementById('downloadPdfBtn').addEventListener('click', () => {
  if (!currentSessionId) return;
  window.open(`/api/tools/chronograph/${currentSessionId}/report.pdf`, '_blank');
});

// ── Upload CSV ────────────────────────────────────────────────────────────────

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

document.getElementById('uploadBtn').addEventListener('click', () => {
  document.getElementById('uploadName').value = '';
  document.getElementById('uploadDate').value = new Date().toISOString().slice(0,10);
  document.getElementById('csvFileInput').value = '';
  document.getElementById('selectedFileName').classList.add('d-none');
  document.getElementById('uploadAlert').classList.add('d-none');
  document.getElementById('uploadSubmitBtn').disabled = true;
  uploadModal.show();
});

// Drag & drop / click on drop area
const dropArea = document.getElementById('dropArea');
dropArea.addEventListener('click', () => document.getElementById('csvFileInput').click());
dropArea.addEventListener('dragover', e => { e.preventDefault(); dropArea.classList.add('drag-over'); });
dropArea.addEventListener('dragleave', () => dropArea.classList.remove('drag-over'));
dropArea.addEventListener('drop', e => {
  e.preventDefault();
  dropArea.classList.remove('drag-over');
  const file = e.dataTransfer.files[0];
  if (file) setSelectedFile(file);
});

document.getElementById('csvFileInput').addEventListener('change', e => {
  const file = e.target.files[0];
  if (file) setSelectedFile(file);
});

function setSelectedFile(file) {
  const nameEl = document.getElementById('selectedFileName');
  nameEl.textContent = `Selected: ${file.name}`;
  nameEl.classList.remove('d-none');
  document.getElementById('uploadSubmitBtn').disabled = false;
  // Pre-fill session name from filename if empty
  const nameInput = document.getElementById('uploadName');
  if (!nameInput.value) {
    nameInput.value = file.name.replace(/\.[^.]+$/, '').replace(/[_-]/g, ' ');
  }
}

document.getElementById('uploadSubmitBtn').addEventListener('click', async () => {
  const alertEl  = document.getElementById('uploadAlert');
  const spinner  = document.getElementById('uploadSpinnerInline');
  const submitBtn = document.getElementById('uploadSubmitBtn');
  alertEl.classList.add('d-none');

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

  const formData = new FormData();
  formData.append('file', file);
  const name = document.getElementById('uploadName').value.trim();
  const date = document.getElementById('uploadDate').value;
  const velUnit    = document.querySelector('input[name="uploadVelUnit"]:checked')?.value || 'fps';
  const chronoType = document.getElementById('uploadChronoType').value;
  if (name) formData.append('name', name);
  if (date) formData.append('date', date);
  formData.append('velocity_unit', velUnit);
  formData.append('chrono_type', chronoType);

  submitBtn.disabled = true;
  spinner.classList.remove('d-none');

  try {
    const session = await apiFetch('/tools/chronograph/upload/', {
      method: 'POST',
      body: formData,
    }).then(async r => {
      if (!r.ok) {
        const err = await r.json().catch(() => ({}));
        throw Object.assign(new Error('Upload failed'), { data: err });
      }
      return r.json();
    });

    sessions.unshift(session);
    renderSessionsList();
    uploadModal.hide();
    selectSession(session.id);
    showToast('Session uploaded and analysed!');
  } catch(e) {
    alertEl.textContent = (e.data && (e.data.detail || JSON.stringify(e.data))) || 'Upload failed.';
    alertEl.classList.remove('d-none');
    submitBtn.disabled = false;
  } finally {
    spinner.classList.add('d-none');
  }
});

// ── Photos per group (one per group) ──────────────────────────────────────────

const photoModal = new bootstrap.Modal('#photoModal');
// Track existing GroupPhoto id for the current modal (null = no existing photo)
let _existingGroupPhotoId = null;

function openPhotoModal(groupId, existingGroupPhotoId = null) {
  _photoTargetGroupId = groupId;
  _existingGroupPhotoId = existingGroupPhotoId;
  document.getElementById('photoFileInput').value = '';
  document.getElementById('photoCaption').value = '';
  document.getElementById('photoAlert').classList.add('d-none');
  const title = document.querySelector('#photoModal .modal-title');
  if (title) title.innerHTML = existingGroupPhotoId
    ? '<i class="bi bi-image me-2"></i>Replace group photo'
    : '<i class="bi bi-image me-2"></i>Add photo to group';
  photoModal.show();
}

async function loadGroupPhotos(groupId) {
  const container = document.getElementById(`photos-${groupId}`);
  if (!container) return;
  try {
    const _gpData = await apiGet(`/photos/group-photos/?shot_group=${groupId}`);
    const items = asList(_gpData);
    if (!items.length) {
      container.innerHTML = `
        <button class="btn btn-sm btn-outline-secondary py-0 px-2"
                onclick="openPhotoModal(${groupId})">
          <i class="bi bi-plus-lg me-1"></i>Add photo
        </button>`;
      return;
    }
    // One photo per group — use first result
    const gp = items[0];
    const analysisHtml = gp.analysis ? (() => {
      const esMm  = gp.analysis.group_size_mm  != null ? parseFloat(gp.analysis.group_size_mm).toFixed(1)  + ' mm'  : '—';
      const esMoa = gp.analysis.group_size_moa != null ? ' / ' + parseFloat(gp.analysis.group_size_moa).toFixed(2) + ' MOA' : '';
      return `<div class="small text-muted mt-1">ES: ${esMm}${esMoa}</div>`;
    })() : '';
    const hasPois = (gp.points_of_impact || []).length >= 2;
    container.innerHTML = `
      <div class="d-flex align-items-start gap-3">
        <img src="/api/photos/${gp.photo.id}/data/"
             style="width:120px;height:90px;object-fit:cover;border-radius:6px;cursor:pointer"
             title="${gp.caption || ''}"
             onclick="window.open('/api/photos/${gp.photo.id}/data/','_blank')">
        <div class="d-flex flex-column gap-1">
          ${gp.caption ? `<span class="small text-muted">${gp.caption}</span>` : ''}
          ${analysisHtml}
          <a href="/group-size.html?gp=${gp.id}" class="btn btn-xs btn-outline-primary py-0 px-2 small">
            <i class="bi bi-crosshair2 me-1"></i>Measure group
          </a>
          ${hasPois ? `<button class="btn btn-xs btn-outline-secondary py-0 px-1 small"
                               onclick="computeGroupSize(${gp.id}, ${groupId})">
                         Recompute
                       </button>` : ''}
          <button class="btn btn-xs btn-outline-secondary py-0 px-2 mt-1"
                  onclick="openPhotoModal(${groupId}, ${gp.id})">
            <i class="bi bi-arrow-repeat me-1"></i>Replace
          </button>
        </div>
      </div>`;
  } catch(e) {
    if (container) container.innerHTML = '<span class="text-danger small">Failed to load photos.</span>';
  }
}

document.getElementById('photoSubmitBtn').addEventListener('click', async () => {
  const alertEl = document.getElementById('photoAlert');
  const spinner = document.getElementById('photoSpinner');
  const submitBtn = document.getElementById('photoSubmitBtn');
  alertEl.classList.add('d-none');

  const file = document.getElementById('photoFileInput').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 {
    // Step 1: if replacing, delete the old GroupPhoto first
    if (_existingGroupPhotoId) {
      await apiDelete(`/photos/group-photos/${_existingGroupPhotoId}/`);
    }

    // Step 2: upload raw photo
    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();
      });

    // Step 3: link to group
    const caption = document.getElementById('photoCaption').value.trim();
    await apiPost('/photos/group-photos/', {
      photo_id: photo.id,
      shot_group: _photoTargetGroupId,
      ...(caption ? { caption } : {}),
    });

    photoModal.hide();
    loadGroupPhotos(_photoTargetGroupId);
    showToast(_existingGroupPhotoId ? 'Photo replaced.' : 'Photo added.');
  } catch(e) {
    alertEl.textContent = (e.data && (e.data.detail || JSON.stringify(e.data))) || 'Upload failed.';
    alertEl.classList.remove('d-none');
  } finally {
    submitBtn.disabled = false;
    spinner.classList.add('d-none');
  }
});

async function computeGroupSize(groupPhotoId, groupId) {
  try {
    await apiPost(`/photos/group-photos/${groupPhotoId}/compute-group-size/`, {});
    loadGroupPhotos(groupId);
    showToast('Group size computed.');
  } catch(e) {
    showToast('Failed to compute group size.', 'danger');
  }
}

// ── Init ──────────────────────────────────────────────────────────────────────
async function init() {
  await loadSessions();
  const params = new URLSearchParams(window.location.search);
  const id = parseInt(params.get('id'), 10);
  if (id && sessions.find(s => s.id === id)) selectSession(id);
}
init();
