import { ActivityStats } from '../types';

export const parseGpxFile = async (file: File): Promise<ActivityStats> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();

    reader.onload = (e) => {
      try {
        const text = e.target?.result as string;
        const parser = new DOMParser();
        const xmlDoc = parser.parseFromString(text, 'text/xml');

        const trkpts = Array.from(xmlDoc.getElementsByTagName('trkpt'));
        
        if (trkpts.length === 0) {
           // Fallback for rtept if no trkpt
           const rtepts = Array.from(xmlDoc.getElementsByTagName('rtept'));
           if (rtepts.length === 0) {
             throw new Error('No track points found in GPX');
           }
        }

        let totalDistance = 0;
        let totalTime = 0;
        let elevationGain = 0;
        let startTime: Date | null = null;
        let endTime: Date | null = null;
        let lastEle: number | null = null;

        for (let i = 0; i < trkpts.length; i++) {
          const lat1 = parseFloat(trkpts[i].getAttribute('lat') || '0');
          const lon1 = parseFloat(trkpts[i].getAttribute('lon') || '0');
          const ele = parseFloat(trkpts[i].getElementsByTagName('ele')[0]?.textContent || '0');
          const timeStr = trkpts[i].getElementsByTagName('time')[0]?.textContent;

          if (i > 0) {
            const lat2 = parseFloat(trkpts[i - 1].getAttribute('lat') || '0');
            const lon2 = parseFloat(trkpts[i - 1].getAttribute('lon') || '0');
            totalDistance += getDistanceFromLatLonInKm(lat1, lon1, lat2, lon2);

            // Elevation gain
            if (lastEle !== null && ele > lastEle) {
                elevationGain += (ele - lastEle);
            }
          }

          if (timeStr) {
            const time = new Date(timeStr);
            if (!startTime) startTime = time;
            endTime = time;
          }
          
          if (!isNaN(ele)) lastEle = ele;
        }

        if (startTime && endTime) {
            totalTime = (endTime.getTime() - startTime.getTime()); // ms
        }

        resolve({
          distance: `${totalDistance.toFixed(2)} km`,
          duration: msToTime(totalTime),
          elevation: `${Math.round(elevationGain)}m`,
        });

      } catch (error) {
        reject(error);
      }
    };

    reader.onerror = () => reject(new Error('Error reading file'));
    reader.readAsText(file);
  });
};

// Haversine formula
function getDistanceFromLatLonInKm(lat1: number, lon1: number, lat2: number, lon2: number) {
  const R = 6371; // Radius of the earth in km
  const dLat = deg2rad(lat2 - lat1);
  const dLon = deg2rad(lon2 - lon1);
  const a =
    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
    Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
    Math.sin(dLon / 2) * Math.sin(dLon / 2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  const d = R * c; // Distance in km
  return d;
}

function deg2rad(deg: number) {
  return deg * (Math.PI / 180);
}

function msToTime(duration: number) {
    if (duration <= 0) return "0h 00m";
    const minutes = Math.floor((duration / (1000 * 60)) % 60);
    const hours = Math.floor((duration / (1000 * 60 * 60)) % 24);
  
    return `${hours}h ${minutes}m`;
  }