import 'package:nmea/nmea.dart';
import 'package:terepi_seged/models/satellite_info.dart';

/// GSA — GNSS DOP és aktív műholdak
///
/// Formátum:
/// $GNGSA,A,3,01,02,03,04,05,06,07,08,09,10,11,12,2.1,1.2,1.7*XX
///         │ │  └─────────── 12 db PRN ────────┘   │   │   │
///         │ └── Fix típus: 1=nincs, 2=2D, 3=3D    │   │   └─ VDOP
///         └──── Mód: M=kézi, A=auto               │   └───── HDOP
///                                                 └───────── PDOP
///
/// NMEA 4.1+: opcionális rendszer azonosító (fields[18])
/// Minden rendszerhez érkezik egy-egy GSA mondat.
class Gngsa extends TalkerSentence {
  static const String id = 'GNGSA';

  Gngsa({required super.raw});

  @override
  bool get valid => super.valid && fields.length >= 18;

  /// Módválasztás: 'M' = kézi, 'A' = automatikus
  String get selectionMode => fields[1];

  /// Fix típus: 1 = nincs, 2 = 2D, 3 = 3D
  int get fixType => int.tryParse(fields[2]) ?? 1;

  /// Fixben használt műholdak PRN számai (max 12, üres mezők kihagyva)
  List<int> get activeSatellitePrns {
    final prns = <int>[];
    for (int i = 3; i <= 14; i++) {
      if (i >= fields.length) break;
      final prn = int.tryParse(fields[i]);
      if (prn != null && prn > 0) prns.add(prn);
    }
    return prns;
  }

  /// PDOP — 3D pozíció pontossági szorzó
  double get pdop => _parseDouble(fields[15]);

  /// HDOP — vízszintes pontossági szorzó
  double get hdop => _parseDouble(fields[16]);

  /// VDOP — függőleges pontossági szorzó
  /// Az utolsó mező checksum előtti részét veszi
  double get vdop {
    if (fields.length <= 17) return 0.0;
    return _parseDouble(fields[17].split('*').first);
  }

  /// GDOP számítása: √(PDOP² + TDOP²)
  /// Közelítés TDOP nélkül: GDOP ≈ PDOP * 1.1
  double get gdopApprox => pdop * 1.1;

  /// Talker azonosító — rendszer meghatározásához
  /// GP=GPS, GL=GLONASS, GA=Galileo, GB/BD=BeiDou, GN=vegyes
  String get talkerId => raw.length >= 3 ? raw.substring(1, 3) : 'GN';

  /// Rendszer neve a talker alapján
  String get systemName => switch (talkerId) {
        'GP' => 'GPS',
        'GL' => 'GLONASS',
        'GA' => 'Galileo',
        'GB' || 'BD' => 'BeiDou',
        'GN' => 'Mixed',
        _ => 'Unknown',
      };

  int? get systemId {
    if (fields.length <= 18) return null;
    final rawSys = fields[18].split('*').first.trim();
    if (rawSys.isEmpty) return null;
    return int.tryParse(rawSys);
  }

  GnssConstellation get constellation {
    switch (systemId) {
      case 1:
        return GnssConstellation.gps;
      case 2:
        return GnssConstellation.glonass;
      case 3:
        return GnssConstellation.galileo;
      case 4:
        return GnssConstellation.beidou;
      case 5:
        return GnssConstellation.qzss;
      default:
        return SatelliteInfo.constellationFromTalker(talkerId);
    }
  }

  String get constellationKey => constellation.name;

  List<String> get activeSatelliteKeys =>
      activeSatellitePrns.map((prn) => '$constellationKey:$prn').toList();

  int get usedSatelliteCount => activeSatellitePrns.length;

  double _parseDouble(String? s) {
    if (s == null || s.isEmpty) return 0.0;
    return double.tryParse(s) ?? 0.0;
  }
}
