import 'dart:math' as math;

// ─── TrackPoint ───────────────────────────────────────────────────────────────

class TrackPoint {
  final int? id;
  final int trackId;
  final double latitude;
  final double longitude;
  final double? altitude;
  final double? accuracy;
  final double? speed; // m/s
  final double? heading;
  final DateTime timestamp;

  const TrackPoint({
    this.id,
    required this.trackId,
    required this.latitude,
    required this.longitude,
    this.altitude,
    this.accuracy,
    this.speed,
    this.heading,
    required this.timestamp,
  });

  Map<String, dynamic> toMap() => {
        if (id != null) 'id': id,
        'track_id': trackId,
        'latitude': latitude,
        'longitude': longitude,
        'altitude': altitude,
        'accuracy': accuracy,
        'speed': speed,
        'heading': heading,
        'timestamp': timestamp.toIso8601String(),
      };

  factory TrackPoint.fromMap(Map<String, dynamic> m) => TrackPoint(
        id: m['id'] as int?,
        trackId: m['track_id'] as int,
        latitude: m['latitude'] as double,
        longitude: m['longitude'] as double,
        altitude: m['altitude'] as double?,
        accuracy: m['accuracy'] as double?,
        speed: m['speed'] as double?,
        heading: m['heading'] as double?,
        timestamp: DateTime.parse(m['timestamp'] as String),
      );
}

// ─── Track státusz ────────────────────────────────────────────────────────────

enum TrackStatus { recording, paused, finished }

enum TrackSyncMode { localOnly, online }

enum TrackSyncStatus { pending, synced, error }
// ─── Track ───────────────────────────────────────────────────────────────────

class Track {
  final int? id;
  final int? projectId;
  final String name;
  final DateTime startTime;
  final DateTime? endTime;
  final TrackStatus status;
  final String source; // pl. "Telefon GPS", "BLE GNSS"

  // Statisztikák — ezeket a DB is tárolja a gyors listázáshoz
  final double distanceMeters;
  final int pointCount;
  final TrackSyncMode syncMode;
  final TrackSyncStatus syncStatus;
  final String? supabaseId;

  const Track(
      {this.id,
      this.projectId,
      required this.name,
      required this.startTime,
      this.endTime,
      this.status = TrackStatus.recording,
      this.source = 'Telefon GPS',
      this.distanceMeters = 0,
      this.pointCount = 0,
      this.syncMode = TrackSyncMode.online,
      this.syncStatus = TrackSyncStatus.pending,
      this.supabaseId});

  Track copyWith(
          {int? id,
          int? projectId,
          String? name,
          DateTime? startTime,
          DateTime? endTime,
          TrackStatus? status,
          String? source,
          double? distanceMeters,
          int? pointCount,
          TrackSyncMode? syncMode,
          TrackSyncStatus? syncStatus,
          String? supabaseId}) =>
      Track(
          id: id ?? this.id,
          projectId: projectId ?? this.projectId,
          name: name ?? this.name,
          startTime: startTime ?? this.startTime,
          endTime: endTime ?? this.endTime,
          status: status ?? this.status,
          source: source ?? this.source,
          distanceMeters: distanceMeters ?? this.distanceMeters,
          pointCount: pointCount ?? this.pointCount,
          syncMode: syncMode ?? this.syncMode,
          syncStatus: syncStatus ?? this.syncStatus,
          supabaseId: supabaseId ?? this.supabaseId);

  /// Formázott időtartam (óó:pp:mm)
  String get durationFormatted {
    final end = endTime ?? DateTime.now();
    final d = end.difference(startTime);
    final h = d.inHours.toString().padLeft(2, '0');
    final m = (d.inMinutes % 60).toString().padLeft(2, '0');
    final s = (d.inSeconds % 60).toString().padLeft(2, '0');
    return '$h:$m:$s';
  }

  /// Formázott távolság
  String get distanceFormatted {
    if (distanceMeters < 1000) {
      return '${distanceMeters.toStringAsFixed(0)} m';
    }
    return '${(distanceMeters / 1000).toStringAsFixed(2)} km';
  }

  Map<String, dynamic> toMap() => {
        if (id != null) 'id': id,
        if (projectId != null) 'project_id': projectId,
        'name': name,
        'start_time': startTime.toIso8601String(),
        'end_time': endTime?.toIso8601String(),
        'status': status.name,
        'source': source,
        'distance_m': distanceMeters,
        'point_count': pointCount,
        'is_local_only': syncMode == TrackSyncMode.localOnly ? 1 : 0,
        'sync_status': syncStatus.name,
        'supabase_id': supabaseId,
      };

  factory Track.fromMap(Map<String, dynamic> m) => Track(
      id: m['id'] as int?,
      projectId: m['project_id'] as int?,
      name: m['name'] as String,
      startTime: DateTime.parse(m['start_time'] as String),
      endTime: m['end_time'] != null
          ? DateTime.parse(m['end_time'] as String)
          : null,
      status: TrackStatus.values.firstWhere(
        (s) => s.name == (m['status'] as String?),
        orElse: () => TrackStatus.finished,
      ),
      source: m['source'] as String? ?? 'Telefon GPS',
      distanceMeters: (m['distance_m'] as num?)?.toDouble() ?? 0,
      pointCount: m['point_count'] as int? ?? 0,
      syncMode: (m['is_local_only'] as int?) == 1
          ? TrackSyncMode.localOnly
          : TrackSyncMode.online,
      syncStatus: TrackSyncStatus.values
          .byName(m['sync_status'] as String? ?? 'pending'),
      supabaseId: m['supabase_id'] as String?);

  bool get isLocalOnly => syncMode == TrackSyncMode.localOnly;
}

// ─── Segédszámítás: Haversine távolság ───────────────────────────────────────

double haversineMeters(double lat1, double lon1, double lat2, double lon2) {
  const r = 6371000.0;
  final dLat = _toRad(lat2 - lat1);
  final dLon = _toRad(lon2 - lon1);
  final a = math.sin(dLat / 2) * math.sin(dLat / 2) +
      math.cos(_toRad(lat1)) *
          math.cos(_toRad(lat2)) *
          math.sin(dLon / 2) *
          math.sin(dLon / 2);
  return r * 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a));
}

double _toRad(double deg) => deg * math.pi / 180;
