const MAX_TRAIL_LENGTH=240,REFRESH_INTERVAL_MS=5e3,ORBIT_DURATION_MS=576e4;function pruneChartData(t){const e=Date.now()-576e4;for(;t.length&&t[0].time{map.setView(INITIAL_MAP_CENTER,INITIAL_MAP_ZOOM)}));const createTerminatorLayer=()=>"function"==typeof L.terminator?L.terminator({fillColor:"#000000",fillOpacity:.2}):L.Terminator?new L.Terminator({fillColor:"#000000",fillOpacity:.2}):(console.warn("Leaflet‑Terminator plugin missing"),null);let terminatorLayer=createTerminatorLayer();function nowUTC(){return new Date}if(terminatorLayer&&terminatorLayer.addTo(map),terminatorLayer&&"function"==typeof terminatorLayer.setTime){const t=()=>{terminatorLayer.setTime(nowUTC()),terminatorLayer.redraw?.()};t(),setInterval(t,6e4)}const infoOverlay=document.getElementById("map-info-overlay"),infoToggle=document.getElementById("info-toggle");infoOverlay&&infoToggle&&infoToggle.addEventListener("click",()=>{infoOverlay.classList.toggle("collapsed")}),L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",{maxZoom:19}).addTo(map);const issIcon=L.icon({iconUrl:"iss.png",iconSize:[50,50],iconAnchor:[25,25],popupAnchor:[0,-25]});let issMarker;const issTrailData=[];let issTrailOld,issTrailRecent;function initializeISSTrail(){issTrailOld=L.polyline([],{color:"rgba(128,128,128,0.5)",weight:2,dashArray:"5, 5",lineCap:"round"}).addTo(map),issTrailRecent=L.polyline([],{color:"green",weight:3,dashArray:"5, 5",lineCap:"round"}).addTo(map)}function wrapLongitude(t){const e=map.getCenter().lng;return[t,t+360,t-360].reduce((t,o)=>Math.abs(o-e)e?(o.push(a),a=[t[i]]):a.push(t[i])}return a.length>0&&o.push(a),o}function updateTrailPolylines(){const t=new Date(Date.now()-576e4),e=[],o=[];issTrailData.forEach(a=>{a.timestamp0&&o.length>0&&o.unshift(e[e.length-1]);const a=segmentizePoints(e),i=segmentizePoints(o);issTrailOld.setLatLngs(a),issTrailRecent.setLatLngs(i)}const altitudeData=[];let altitudeChart;function initializeAltitudeChart(){const t=document.getElementById("altitudeChart").getContext("2d");altitudeChart=new Chart(t,{type:"line",data:{datasets:[{label:"Altitude (km)",data:[],borderColor:"#FFD700",backgroundColor:"transparent",borderWidth:2,tension:.25,pointRadius:t=>t.dataIndex===t.dataset.data.length-1?5:0,pointBackgroundColor:"#FFD700",pointHoverRadius:6}]},options:{responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1}},scales:{x:{type:"time",time:{unit:"minute",tooltipFormat:"HH:mm:ss",displayFormats:{minute:"HH:mm"}},grid:{color:"#666"},ticks:{color:"#ddd",font:{size:10}}},y:{title:{display:!0,text:"Altitude (km)",color:"#ddd",font:{size:12}},grid:{color:"#666"},ticks:{color:"#ddd",font:{size:10}}}}}})}function updateAltitudeChart(){pruneChartData(altitudeData);const t=getISSXRatio(),e=Date.now()+576e4*(1-t),o=e-576e4;altitudeChart.options.scales.x.min=o,altitudeChart.options.scales.x.max=e,altitudeChart.data.datasets[0].data=altitudeData.map(t=>({x:t.time,y:t.altitude})),altitudeChart.update("none")}const velocityData=[];let velocityChart;function initializeVelocityChart(){const t=document.getElementById("velocityChart").getContext("2d");velocityChart=new Chart(t,{type:"line",data:{datasets:[{label:"Velocity (km/h)",data:[],borderColor:"#1e90ff",backgroundColor:"transparent",borderWidth:2,tension:.25,pointRadius:t=>t.dataIndex===t.dataset.data.length-1?5:0,pointBackgroundColor:"#1e90ff",pointHoverRadius:6}]},options:{responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1}},scales:{x:{type:"time",time:{unit:"minute",tooltipFormat:"HH:mm:ss",displayFormats:{minute:"HH:mm"}},grid:{color:"#666"},ticks:{color:"#ddd",font:{size:10}}},y:{title:{display:!0,text:"Velocity (km/h)",color:"#ddd",font:{size:12}},grid:{color:"#666"},ticks:{color:"#ddd",font:{size:10}}}}}})}function updateVelocityChart(){pruneChartData(velocityData);const t=getISSXRatio(),e=Date.now()+576e4*(1-t),o=e-576e4;velocityChart.options.scales.x.min=o,velocityChart.options.scales.x.max=e,velocityChart.data.datasets[0].data=velocityData.map(t=>({x:t.time,y:t.velocity})),velocityChart.update("none")}async function fetchHistory(){try{const t=await fetch("https://api.issinfo.net/isshistory");(await t.json()).forEach(t=>{const e=+t.latitude,o=wrapLongitude(+t.longitude),a=new Date(t.fetched_at);issTrailData.push({position:[e,o],timestamp:a}),altitudeData.push({time:a,altitude:+t.altitude}),velocityData.push({time:a,velocity:+t.velocity})}),updateTrailPolylines(),updateAltitudeChart(),updateVelocityChart()}catch(t){console.error("Error fetching ISS history:",t)}}async function updateISSLocation(){try{const t=await fetch("https://api.issinfo.net/iss"),e=await t.json(),{latitude:o,longitude:a}=e,i=[+o,wrapLongitude(+a)];issMarker?issMarker.setLatLng(i):issMarker=L.marker(i,{icon:issIcon}).addTo(map),issTrailData.push({position:i,timestamp:new Date}),issTrailData.length>240&&issTrailData.shift(),updateTrailPolylines(),updateMapInfoOverlay(e),altitudeData.push({time:new Date,altitude:+e.altitude}),velocityData.push({time:new Date,velocity:+e.velocity}),altitudeData.length>240&&altitudeData.shift(),velocityData.length>240&&velocityData.shift(),updateAltitudeChart(),updateVelocityChart()}catch(t){console.error("Error fetching ISS data:",t)}}let userLocationMarker=null,visitorLocationMarkers=[];const showLocationToggle=document.getElementById("showLocationToggle"),userLocationIcon=L.icon({iconUrl:"ts-map-pin.png",iconSize:[38,41],iconAnchor:[19,41],popupAnchor:[1,-34]});function addUserLocationMarker(t,e){userLocationMarker?userLocationMarker.setLatLng([t,e]):(userLocationMarker=L.marker([t,e],{icon:userLocationIcon}).addTo(map),userLocationMarker.bindTooltip("Your Location",{permanent:!1,direction:"top"}))}function removeUserLocationMarker(){userLocationMarker&&(map.removeLayer(userLocationMarker),userLocationMarker=null)}function updateUserLocation(){if(!navigator.geolocation)return alert("Geolocation is not supported by your browser."),void(showLocationToggle.checked=!1);navigator.geolocation.getCurrentPosition(t=>{const{latitude:e,longitude:o}=t.coords;addUserLocationMarker(e,o)},t=>{alert("Unable to retrieve your location."),showLocationToggle.checked=!1,removeUserLocationMarker()},{enableHighAccuracy:!0,timeout:1e4})}async function fetchVisitorLocations(){try{const t=await fetch("/api/analytics/visitor-locations");if(!t.ok)return void console.error("Failed to fetch visitor locations:",t.status);const e=await t.json(),o=new Set(visitorLocationMarkers.map(t=>`${t.getLatLng().lat},${t.getLatLng().lng}`));visitorLocationMarkers.forEach(t=>map.removeLayer(t)),visitorLocationMarkers=[],e.locations&&e.locations.length>0&&e.locations.forEach(t=>{if(t.lat&&t.lon){const e=`${t.lat},${t.lon}`,a=!o.has(e),i=L.circleMarker([t.lat,t.lon],{radius:3,fillColor:a?"#00ff00":"#ff6b6b",color:a?"#00ff00":"#ff6b6b",weight:1,opacity:.8,fillOpacity:.6}).addTo(map),n=t.country||"Unknown Location";i.bindTooltip(n,{permanent:!1,direction:"top",className:"visitor-location-tooltip"}),a&&(i.setRadius(8),i.setStyle({fillOpacity:1,opacity:1}),setTimeout(()=>{i.setRadius(3),i.setStyle({fillColor:"#ff6b6b",color:"#ff6b6b",fillOpacity:.6,opacity:.8})},1e3)),visitorLocationMarkers.push(i)}})}catch(t){console.error("Error fetching visitor locations:",t)}}async function init(){initializeISSTrail(),initializeAltitudeChart(),initializeVelocityChart(),await fetchHistory(),updateISSLocation(),setInterval(updateISSLocation,5e3),await fetchVisitorLocations(),setInterval(fetchVisitorLocations,5e3)}showLocationToggle&&showLocationToggle.addEventListener("change",function(){this.checked?updateUserLocation():removeUserLocationMarker()}),init(),function(){const t=document.querySelectorAll(".time-in-space");function e(){const e=Date.now(),o=window.innerWidth>=768;t.forEach(t=>{let a=Number(t.dataset.launched);a<1e12&&(a*=1e3),Number.isNaN(a)||(t.textContent=function(t,e){let o=Math.floor(t/1e3);const a=Math.floor(o/86400);o%=86400;const i=Math.floor(o/3600);o%=3600;const n=Math.floor(o/60);return o%=60,e?`${a}d ${i}h ${n}m ${o}s`:`${a}d ${i}h ${n}m`}(e-a,o))})}t.length&&(e(),setInterval(e,1e3))}();