let pyrkLiveWatchId = null;
let pyrkLiveMarker = null;
let pyrkLiveCircle = null;
let pyrkWalkRouteState = null;
let pyrkRouteStopsCollapsed = null;

function readPointLat(point) {
  const value = point.lat ?? point.latitude;
  const number = Number(value);
  return Number.isFinite(number) ? number : null;
}

function readPointLng(point) {
  const value = point.lng ?? point.longitude;
  const number = Number(value);
  return Number.isFinite(number) ? number : null;
}

function normalizedPoint(point, index) {
  const lat = readPointLat(point);
  const lng = readPointLng(point);
  return {
    ...point,
    id: Number(point.id || 0),
    lat,
    lng,
    sort_order: Number(point.sort_order || (index + 1)),
    point_type: point.point_type || 'checkpoint',
    title: point.title || `Point ${index + 1}`,
    description: point.description || '',
    navigation_note: point.navigation_note || '',
    checkin_radius_meters: Number(point.checkin_radius_meters || 60),
    is_navigation_stop: Object.prototype.hasOwnProperty.call(point, 'is_navigation_stop') ? Number(point.is_navigation_stop || 0) : null,
  };
}

function buildGoogleDirectionsUrl(points) {
  const valid = (points || []).filter(p => Number.isFinite(Number(p.lat)) && Number.isFinite(Number(p.lng)));
  if (!valid.length) return '';
  const origin = valid[0];
  const destination = valid[valid.length - 1];
  const waypoints = valid.slice(1, -1).slice(0, 9).map(p => `${Number(p.lat)},${Number(p.lng)}`).join('|');
  let url = `https://www.google.com/maps/dir/?api=1&travelmode=walking&origin=${encodeURIComponent(Number(origin.lat) + ',' + Number(origin.lng))}&destination=${encodeURIComponent(Number(destination.lat) + ',' + Number(destination.lng))}`;
  if (waypoints) url += `&waypoints=${encodeURIComponent(waypoints)}`;
  return url;
}

function buildGoogleNextStopUrl(point) {
  if (!point || !Number.isFinite(Number(point.lat)) || !Number.isFinite(Number(point.lng))) return '';
  return `https://www.google.com/maps/dir/?api=1&travelmode=walking&dir_action=navigate&destination=${encodeURIComponent(Number(point.lat) + ',' + Number(point.lng))}`;
}

function setupGoogleNavigationButton(points) {
  const btn = document.getElementById('openGoogleNavigationBtn');
  if (!btn) return;

  const valid = (points || []).filter(p => Number.isFinite(Number(p.lat)) && Number.isFinite(Number(p.lng)));
  if (valid.length >= 2 && valid.length <= 5) {
    const url = buildGoogleDirectionsUrl(valid);
    if (url) {
      btn.href = url;
      btn.textContent = 'Open route overview in Google Maps';
      btn.hidden = false;
      return;
    }
  }

  btn.hidden = true;
}

function routePointLabel(type) {
  return ({start:'Start', end:'Finish', checkpoint:'Checkpoint', water_station:'Water', medical_station:'Medical', rest_station:'Rest', station:'Station'}[type] || 'Point');
}

function routePointIcon(type) {
  return ({start:'🚩', end:'🏁', checkpoint:'✅', water_station:'💧', medical_station:'➕', rest_station:'☕', station:'📍'}[type] || '📍');
}

function isNavigationStop(point) {
  if (point.is_navigation_stop !== null) return Number(point.is_navigation_stop) === 1;
  return ['start', 'checkpoint', 'end'].includes(point.point_type) || Number(point.is_required_checkpoint || 0) === 1;
}

function completedMap(progress, logs) {
  const out = {};
  const completed = progress && progress.completed_ids ? progress.completed_ids : {};
  Object.keys(completed || {}).forEach(id => { out[Number(id)] = completed[id] || true; });
  (logs || []).forEach(log => { out[Number(log.route_point_id)] = log.scanned_at || true; });
  return out;
}

function nextNavigationPoint(points, doneMap) {
  return (points || []).find(p => isNavigationStop(p) && p.id && !doneMap[p.id]) || null;
}

function formatPercent(done, total) {
  if (!total) return 0;
  return Math.min(100, Math.round((done / total) * 100));
}

function applyRouteStopsCollapsedState(count) {
  const list = document.getElementById('routeStopsList');
  const btn = document.getElementById('toggleRouteStopsBtn');
  const toolbar = document.getElementById('routeStopsToolbar');
  const countEl = document.getElementById('routeStopsCount');
  if (toolbar) toolbar.hidden = !count;
  if (countEl) countEl.textContent = `${count} ${count === 1 ? 'stop' : 'stops'}`;
  if (!list || !btn) return;

  const collapsed = !!pyrkRouteStopsCollapsed;
  list.hidden = collapsed;
  list.classList.toggle('is-collapsed', collapsed);
  btn.setAttribute('aria-expanded', collapsed ? 'false' : 'true');
  btn.textContent = collapsed ? `Show checkpoints (${count})` : 'Hide checkpoints';
}

function setRouteStopsCollapsed(collapsed, count) {
  pyrkRouteStopsCollapsed = !!collapsed;
  applyRouteStopsCollapsedState(count || (pyrkWalkRouteState?.navPoints?.length || 0));
}

function setupSmartRouteNavigation(detail) {
  const panel = document.getElementById('routeNavigationPanel');
  if (!panel || !detail || !detail.walk) return;

  const points = (detail.points || []).map(normalizedPoint).filter(p => Number.isFinite(p.lat) && Number.isFinite(p.lng));
  const navPoints = points.filter(isNavigationStop);
  if (!navPoints.length) {
    panel.hidden = true;
    applyRouteStopsCollapsedState(0);
    return;
  }
  if (pyrkRouteStopsCollapsed === null) {
    pyrkRouteStopsCollapsed = navPoints.length > 6;
  }

  const walk = detail.walk || {};
  const progress = detail.my_checkpoint_progress || {};
  const logs = detail.my_checkpoint_logs || [];
  const doneMap = completedMap(progress, logs);
  const doneNavCount = navPoints.filter(p => doneMap[p.id]).length;
  const percent = formatPercent(doneNavCount, navPoints.length);
  const next = nextNavigationPoint(navPoints, doneMap);
  const isCheckedIn = Number(walk.is_checked_in_by_me || 0) === 1 || !!walk.my_check_in_time;
  const isFinished = Number(walk.is_finished_by_me || 0) === 1 || Number(walk.is_partially_completed_by_me || 0) === 1;

  pyrkWalkRouteState = {detail, points, navPoints, doneMap, next, isCheckedIn, isFinished};
  panel.hidden = false;

  const ring = document.getElementById('routeProgressRing');
  if (ring) ring.textContent = `${percent}%`;

  const summary = document.getElementById('routeProgressSummary');
  if (summary) {
    summary.innerHTML = `
      <div><strong>${doneNavCount}</strong><span>completed</span></div>
      <div><strong>${navPoints.length}</strong><span>route stops</span></div>
      <div><strong>${Number(walk.total_km || 0).toFixed(2)}</strong><span>KM route</span></div>
      <div><strong>${isCheckedIn ? 'Active' : 'Not checked in'}</strong><span>status</span></div>`;
  }

  const nextBadge = document.getElementById('routeNextBadge');
  const nextTitle = document.getElementById('routeNextTitle');
  const nextDesc = document.getElementById('routeNextDescription');
  const navBtn = document.getElementById('navigateNextCheckpointBtn');
  const markBtn = document.getElementById('markCheckpointBtn');

  if (next) {
    if (nextBadge) nextBadge.textContent = isCheckedIn ? 'Next stop' : 'Next stop after check-in';
    if (nextTitle) nextTitle.textContent = `${routePointIcon(next.point_type)} ${next.title}`;
    if (nextDesc) {
      const note = next.navigation_note || next.description || `${routePointLabel(next.point_type)} ${next.sort_order} · GPS radius ${Number(next.checkin_radius_meters || 60)}m`;
      nextDesc.textContent = note;
    }
    if (navBtn) {
      const url = buildGoogleNextStopUrl(next);
      navBtn.href = url || '#';
      navBtn.hidden = !url;
      navBtn.textContent = 'Navigate to next point';
    }
    if (markBtn) {
      markBtn.hidden = isFinished;
      markBtn.disabled = !isCheckedIn;
      markBtn.textContent = isCheckedIn ? 'I reached this point' : 'Check in first';
      markBtn.dataset.routePointId = String(next.id);
    }
  } else {
    if (nextBadge) nextBadge.textContent = 'Route completed';
    if (nextTitle) nextTitle.textContent = 'All required route stops are completed.';
    if (nextDesc) nextDesc.textContent = 'Great work. Pyrk has recorded your route progress.';
    if (navBtn) navBtn.hidden = true;
    if (markBtn) markBtn.hidden = true;
  }

  const list = document.getElementById('routeStopsList');
  if (list) {
    list.innerHTML = navPoints.map((point, index) => {
      const done = !!doneMap[point.id];
      const active = next && point.id === next.id;
      const note = point.navigation_note || point.description || `${Number(point.lat).toFixed(5)}, ${Number(point.lng).toFixed(5)}`;
      return `<article class="route-stop-card ${done ? 'is-done' : ''} ${active ? 'is-current' : ''}">
        <span class="route-stop-number">${done ? '✓' : index + 1}</span>
        <div>
          <strong>${routePointIcon(point.point_type)} ${Pyrk.esc(point.title)}</strong>
          <small>${Pyrk.esc(routePointLabel(point.point_type))} · ${Pyrk.esc(note)}</small>
        </div>
        <a href="${Pyrk.esc(buildGoogleNextStopUrl(point))}" target="_blank" rel="noopener" class="btn btn-light btn-small">Map</a>
      </article>`;
    }).join('');
    applyRouteStopsCollapsedState(navPoints.length);
  }
}

async function getCurrentPositionForCheckpoint() {
  if (window.PyrkNativeDevice?.isAvailable('geolocation')) {
    return await window.PyrkNativeDevice.getCurrentPosition({
      enableHighAccuracy: true,
      maximumAge: 0,
      timeout: 15000
    });
  }

  return await new Promise((resolve, reject) => {
    if (!navigator.geolocation) {
      reject(new Error('This device does not support GPS location.'));
      return;
    }
    navigator.geolocation.getCurrentPosition(resolve, reject, {
      enableHighAccuracy: true,
      maximumAge: 0,
      timeout: 15000,
    });
  });
}

function pyrkLocationSupported() {
  return !!(window.PyrkNativeDevice?.isAvailable('geolocation') || navigator.geolocation);
}

async function pyrkWatchLocation(success, failure, options) {
  if (window.PyrkNativeDevice?.isAvailable('geolocation')) {
    return await window.PyrkNativeDevice.watchPosition(success, failure, options);
  }
  if (!navigator.geolocation) throw new Error('Live location is not supported on this device.');
  return navigator.geolocation.watchPosition(success, failure, options);
}

async function pyrkClearLocationWatch(id) {
  if (id === null || id === undefined) return;
  if (typeof id === 'string' && window.PyrkNativeDevice?.isAvailable('geolocation')) {
    await window.PyrkNativeDevice.clearWatch(id);
    return;
  }
  if (navigator.geolocation) navigator.geolocation.clearWatch(id);
}

async function refreshWalkDetail() {
  if (!window.PYRK_WALK_ID) return null;
  const res = await Pyrk.get('walks.php', {action:'detail', id: window.PYRK_WALK_ID});
  if (!res.ok) return null;
  setupSmartRouteNavigation(res.data || {});
  setupGoogleNavigationButton((res.data.points || []).map(normalizedPoint));
  return res.data;
}

window.refreshPyrkWalkRouteNavigation = refreshWalkDetail;

async function markNextCheckpoint() {
  const msg = document.getElementById('routeNavigationMsg');
  const btn = document.getElementById('markCheckpointBtn');
  const pointId = Number(btn?.dataset.routePointId || 0);
  if (!pointId || !window.PYRK_WALK_ID) return;
  if (msg) { msg.textContent = 'Checking your GPS location...'; msg.className = 'notice'; }
  if (btn) btn.disabled = true;

  try {
    const position = await getCurrentPositionForCheckpoint();
    const res = await Pyrk.post('attendance.php', {
      action: 'self_checkpoint',
      walk_id: window.PYRK_WALK_ID,
      route_point_id: pointId,
      latitude: position.coords.latitude,
      longitude: position.coords.longitude,
      accuracy_meters: position.coords.accuracy || null,
    });

    if (msg) { msg.textContent = res.message || ''; msg.className = 'notice ' + (res.ok ? 'ok' : 'bad'); }
    if (res.ok) await refreshWalkDetail();
    else if (btn) btn.disabled = false;
  } catch (error) {
    if (msg) {
      msg.textContent = error && error.message ? error.message : 'Could not access GPS location. Please allow location permission and try again.';
      msg.className = 'notice bad';
    }
    if (btn) btn.disabled = false;
  }
}

function setupLiveLocation(map, isGoogle) {
  const btn = document.getElementById('startLiveLocationBtn');
  const status = document.getElementById('liveLocationStatus');
  if (!btn) return;

  if (!pyrkLocationSupported()) {
    btn.disabled = true;
    if (status) status.textContent = 'Live location is not supported on this device.';
    return;
  }

  btn.addEventListener('click', async () => {
    if (pyrkLiveWatchId !== null) {
      await pyrkClearLocationWatch(pyrkLiveWatchId);
      pyrkLiveWatchId = null;
      btn.textContent = 'Share my live location';
      if (status) status.textContent = 'Live location stopped.';
      return;
    }

    btn.disabled = true;
    btn.textContent = 'Stop sharing location';
    if (status) status.textContent = 'Waiting for GPS permission...';

    try {
      pyrkLiveWatchId = await pyrkWatchLocation(pos => {
      const lat = pos.coords.latitude;
      const lng = pos.coords.longitude;
      const accuracy = pos.coords.accuracy || 0;

      if (isGoogle && window.google && map) {
        const position = {lat, lng};
        if (!pyrkLiveMarker) pyrkLiveMarker = new google.maps.Marker({map, position, title: 'My live location'});
        else pyrkLiveMarker.setPosition(position);
        if (!pyrkLiveCircle) pyrkLiveCircle = new google.maps.Circle({map, center: position, radius: accuracy, strokeOpacity: .3, fillOpacity: .08});
        else { pyrkLiveCircle.setCenter(position); pyrkLiveCircle.setRadius(accuracy); }
        map.panTo(position);
      } else if (map && window.L) {
        const latLng = [lat, lng];
        if (!pyrkLiveMarker) pyrkLiveMarker = L.marker(latLng).addTo(map).bindPopup('My live location');
        else pyrkLiveMarker.setLatLng(latLng);
        if (!pyrkLiveCircle) pyrkLiveCircle = L.circle(latLng, {radius: accuracy}).addTo(map);
        else { pyrkLiveCircle.setLatLng(latLng); pyrkLiveCircle.setRadius(accuracy); }
        map.panTo(latLng);
      }

      if (status) status.textContent = `Live location active · accuracy ${Math.round(accuracy)}m`;
      }, err => {
        if (status) status.textContent = err.message || 'Could not access location.';
        btn.textContent = 'Share my live location';
        const failedWatch = pyrkLiveWatchId;
        pyrkLiveWatchId = null;
        if (failedWatch !== null) pyrkClearLocationWatch(failedWatch).catch(() => {});
      }, {enableHighAccuracy: true, maximumAge: 5000, timeout: 15000, minimumUpdateInterval: 3000});
      btn.disabled = false;
    } catch (error) {
      pyrkLiveWatchId = null;
      btn.disabled = false;
      btn.textContent = 'Share my live location';
      if (status) status.textContent = error?.message || 'Could not access location.';
    }
  });
}

window.initPyrkWalkMap = async function initPyrkWalkMap() {
  const el = document.getElementById('walkMap');
  if (!el || !window.PYRK_WALK_ID) return;

  const res = await Pyrk.get('walks.php', {action:'detail', id: window.PYRK_WALK_ID});
  if (!res.ok || !res.data.walk) return;

  const points = (res.data.points || []).map(normalizedPoint);
  const valid = points.filter(p => Number.isFinite(p.lat) && Number.isFinite(p.lng));
  const center = valid[0] ? {lat: valid[0].lat, lng: valid[0].lng} : (window.PYRK_MAP_CENTER || {lat:33.8938,lng:35.5018});
  const provider = window.PYRK_MAP_PROVIDER || 'google';

  setupSmartRouteNavigation(res.data);
  setupGoogleNavigationButton(valid);

  if (provider === 'osm' && window.L) {
    const map = L.map(el).setView([center.lat, center.lng], 14);
    setupLiveLocation(map, false);
    L.tileLayer(window.PYRK_OSM_TILE_URL || 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
      maxZoom: 19,
      attribution: window.PYRK_OSM_ATTRIBUTION || '&copy; OpenStreetMap contributors'
    }).addTo(map);

    const boundsPoints = [];
    valid.forEach((p, i) => {
      const latLng = [p.lat, p.lng];
      boundsPoints.push(latLng);
      L.marker(latLng).addTo(map).bindTooltip(String(i+1), {permanent: true, direction: 'top'}).bindPopup(Pyrk.esc(p.title || `Point ${i+1}`));
    });

    let lineCoords = parseStoredGeoJsonLine(res.data.walk.google_polyline);
    if (!lineCoords.length && valid.length > 1) lineCoords = valid.map(p => [p.lat, p.lng]);
    if (lineCoords.length > 1) {
      L.polyline(lineCoords, {weight: 5, opacity: 0.9}).addTo(map);
      boundsPoints.push(...lineCoords);
    }
    if (boundsPoints.length) map.fitBounds(L.latLngBounds(boundsPoints), {padding: [20,20]});
    return;
  }

  if (!window.google) return;
  const map = new google.maps.Map(el, {center, zoom: 14, mapTypeControl: false, streetViewControl: false});
  setupLiveLocation(map, true);
  setupGoogleWalkSearch(map);
  const bounds = new google.maps.LatLngBounds();
  valid.forEach((p, i) => {
    const pos = {lat:p.lat,lng:p.lng}; bounds.extend(pos);
    new google.maps.Marker({map, position: pos, label: String(i+1), title: p.title});
  });
  const polyline = res.data.walk.google_polyline;
  if (polyline && google.maps.geometry && !polyline.trim().startsWith('{')) {
    const path = google.maps.geometry.encoding.decodePath(polyline);
    new google.maps.Polyline({map, path, strokeOpacity:.9, strokeWeight:5});
    path.forEach(p => bounds.extend(p));
  } else if (valid.length > 1) {
    new google.maps.Polyline({map, path: valid.map(p => ({lat:p.lat,lng:p.lng})), strokeOpacity:.9, strokeWeight:5});
  }
  if (!bounds.isEmpty()) map.fitBounds(bounds);
};

function parseStoredGeoJsonLine(value) {
  if (!value || typeof value !== 'string' || !value.trim().startsWith('{')) return [];
  try {
    const geo = JSON.parse(value);
    return (geo.coordinates || []).map(pair => [Number(pair[1]), Number(pair[0])]).filter(pair => Number.isFinite(pair[0]) && Number.isFinite(pair[1]));
  } catch {
    return [];
  }
}

function setupGoogleWalkSearch(map) {
  const input = document.getElementById('walkMapSearch');
  if (!input || !map || !window.google || !google.maps || !google.maps.places) return;

  const searchBox = new google.maps.places.SearchBox(input);
  let searchMarker = null;

  map.addListener('bounds_changed', () => {
    try { searchBox.setBounds(map.getBounds()); } catch (e) {}
  });

  searchBox.addListener('places_changed', () => {
    const places = searchBox.getPlaces() || [];
    if (!places.length) return;

    const bounds = new google.maps.LatLngBounds();
    let firstPlace = null;
    places.forEach(place => {
      if (!place.geometry || !place.geometry.location) return;
      if (!firstPlace) firstPlace = place;
      if (place.geometry.viewport) bounds.union(place.geometry.viewport);
      else bounds.extend(place.geometry.location);
    });

    if (!firstPlace) return;
    if (searchMarker && searchMarker.setMap) searchMarker.setMap(null);
    searchMarker = new google.maps.Marker({
      map,
      position: firstPlace.geometry.location,
      title: firstPlace.name || input.value || 'Searched location',
      animation: google.maps.Animation.DROP
    });

    if (!bounds.isEmpty()) map.fitBounds(bounds);
    map.setZoom(Math.min(map.getZoom() || 16, 17));
  });
}

document.addEventListener('DOMContentLoaded', () => {
  document.getElementById('markCheckpointBtn')?.addEventListener('click', markNextCheckpoint);
  document.getElementById('toggleRouteStopsBtn')?.addEventListener('click', () => {
    setRouteStopsCollapsed(!pyrkRouteStopsCollapsed);
  });
  if (window.PYRK_MAP_PROVIDER === 'osm') window.initPyrkWalkMap();
});
