/**
 * Google Maps GeoJSON Parser
 * Parses saved places exported from Google Takeout
 */

// Google Maps export format from Takeout
export interface GoogleMapsFeature {
  type: 'Feature';
  geometry: {
    type: 'Point';
    coordinates: [number, number]; // [longitude, latitude] - GeoJSON order
  };
  properties: {
    Title?: string;
    Note?: string;
    Updated?: string;
    URL?: string;
    // Google Maps sometimes uses different property names
    title?: string;
    name?: string;
    description?: string;
  };
}

export interface GoogleMapsGeoJSON {
  type: 'FeatureCollection';
  features: GoogleMapsFeature[];
}

export interface ParsedPlace {
  name: string;
  latitude: number;
  longitude: number;
  note?: string;
  url?: string;
  updatedAt?: Date;
}

export interface ParseResult {
  success: boolean;
  places: ParsedPlace[];
  error?: string;
}

/**
 * Validates that the data is a valid GeoJSON FeatureCollection
 */
export function validateGeoJSON(data: unknown): data is GoogleMapsGeoJSON {
  if (!data || typeof data !== 'object') {
    return false;
  }

  const obj = data as Record<string, unknown>;

  // Check for FeatureCollection type
  if (obj.type !== 'FeatureCollection') {
    return false;
  }

  // Check for features array
  if (!Array.isArray(obj.features)) {
    return false;
  }

  return true;
}

/**
 * Validates a single feature from the GeoJSON
 */
function isValidFeature(feature: unknown): feature is GoogleMapsFeature {
  if (!feature || typeof feature !== 'object') {
    return false;
  }

  const f = feature as Record<string, unknown>;

  // Must be a Feature
  if (f.type !== 'Feature') {
    return false;
  }

  // Must have geometry
  if (!f.geometry || typeof f.geometry !== 'object') {
    return false;
  }

  const geometry = f.geometry as Record<string, unknown>;

  // Must be a Point
  if (geometry.type !== 'Point') {
    return false;
  }

  // Must have coordinates array with at least 2 numbers
  if (!Array.isArray(geometry.coordinates) || geometry.coordinates.length < 2) {
    return false;
  }

  const [lng, lat] = geometry.coordinates;
  if (typeof lng !== 'number' || typeof lat !== 'number') {
    return false;
  }

  // Validate coordinate ranges
  if (lat < -90 || lat > 90 || lng < -180 || lng > 180) {
    return false;
  }

  return true;
}

/**
 * Extracts the name from a feature's properties
 */
function extractName(properties: GoogleMapsFeature['properties']): string {
  return (
    properties.Title ||
    properties.title ||
    properties.name ||
    'Unnamed Place'
  );
}

/**
 * Extracts the note/description from a feature's properties
 */
function extractNote(properties: GoogleMapsFeature['properties']): string | undefined {
  return properties.Note || properties.description || undefined;
}

/**
 * Parses Google Maps GeoJSON data and extracts places
 */
export function parseGoogleMapsGeoJSON(jsonString: string): ParseResult {
  let data: unknown;

  // Parse JSON
  try {
    data = JSON.parse(jsonString);
  } catch {
    return {
      success: false,
      places: [],
      error: 'Invalid JSON format. Please ensure the file is valid JSON.',
    };
  }

  // Validate GeoJSON structure
  if (!validateGeoJSON(data)) {
    return {
      success: false,
      places: [],
      error: 'Invalid GeoJSON format. Please upload a GeoJSON file from Google Takeout.',
    };
  }

  // Extract places from features
  const places: ParsedPlace[] = [];

  for (const feature of data.features) {
    if (!isValidFeature(feature)) {
      // Skip invalid features but continue processing
      continue;
    }

    const [longitude, latitude] = feature.geometry.coordinates;
    const properties = feature.properties || {};

    places.push({
      name: extractName(properties),
      latitude,
      longitude,
      note: extractNote(properties),
      url: properties.URL,
      updatedAt: properties.Updated ? new Date(properties.Updated) : undefined,
    });
  }

  if (places.length === 0) {
    return {
      success: false,
      places: [],
      error: 'No valid places found in this file. Make sure the file contains Point features.',
    };
  }

  return {
    success: true,
    places,
  };
}

/**
 * Maximum file size for import (5MB)
 */
export const MAX_FILE_SIZE = 5 * 1024 * 1024;

/**
 * Validates file size
 */
export function validateFileSize(file: File): boolean {
  return file.size <= MAX_FILE_SIZE;
}

/**
 * Formats file size for display
 */
export function formatFileSize(bytes: number): string {
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}
