import 'dart:math' as math;

enum GnssConstellation {
  gps,
  glonass,
  galileo,
  beidou,
  qzss,
  sbas,
  navic,
  mixed,
  unknown,
}

// ─── SatelliteInfo modell ──────────────────────────────────────────────────

/// Egyetlen látható műhold adatai — a skyplot és az SNR diagram alapja.
class SatelliteInfo {
  /// Műhold PRN/SVID azonosítója
  final int prn;

  /// Eleváció fokban (0–90°, 90 = zenit)
  final int elevation;

  /// Azimut fokban (0–359°, 0/360 = É, 90 = K)
  final int azimuth;

  /// Jelerősség dB-Hz-ben (0–99, 0 = nem tracking)
  final int snr;

  /// A műhold konstellációja
  final GnssConstellation constellation;

  // Opcionális: NMEA signal ID (pl. L1/L2/E1/...)
  final int? signalId;

  const SatelliteInfo(
      {required this.prn,
      required this.elevation,
      required this.azimuth,
      required this.snr,
      required this.constellation,
      this.signalId});

  String get system => switch (constellation) {
        GnssConstellation.gps => 'GPS',
        GnssConstellation.glonass => 'GLONASS',
        GnssConstellation.galileo => 'Galileo',
        GnssConstellation.beidou => 'BeiDou',
        GnssConstellation.qzss => 'QZSS',
        GnssConstellation.sbas => 'SBAS',
        GnssConstellation.navic => 'NavIC',
        GnssConstellation.mixed => 'Mixed',
        GnssConstellation.unknown => 'Unknown',
      };

  /// Egyedi kulcs ugyanazon konstellacio azonos muholdjahoz
  String get satelliteKey => '${constellation.name}:$prn';

  /// Egyedi kulcs ugyanazon signal streamhez
  String get signalKey => '${constellation.name}:$prn:${signalId ?? -1}';

  /// Human-readable sav/frekvencia becsles signalId alapjan
  String get bandLabel => _bandLabel(constellation, signalId);

  // ── Minősítési segédek ────────────────────────────────────────────

  /// Erős jel — fixben megbízhatóan részt vesz
  bool get isStrong => snr >= 40;

  /// Jelszint alapjan varhatoan hasznalhato jel.
  /// A valodi "used in fix" allapotot a GSA mondatok alapjan allapitsuk meg.
  bool get hasUsableSignal => snr >= 30;

  /// Gyenge de látható jel
  bool get isWeak => snr > 0 && snr < 30;

  /// Egyáltalán látható-e (snr > 0)
  bool get isVisible => snr > 0;

  // ── Polár koordináta számítás a skyplot CustomPainter-hez ────────

  /// Normalizált sugár (0.0 = zenit, 1.0 = horizont)
  double get polarRadius => 1.0 - (elevation / 90.0);

  /// Szög radiánban a polár koordinátához
  /// (azimut → matematikai szög: É=felső, K=jobb)
  double get polarAngleRad => (azimuth - 90) * math.pi / 180.0;

  /// Polár koordináta pixel pozíciójának kiszámítása
  /// [center] a kör középpontja, [radius] a horizont kör sugara
  ({double dx, double dy}) toOffset(
      double centerX, double centerY, double radius) {
    return (
      dx: centerX + radius * polarRadius * math.cos(polarAngleRad),
      dy: centerY + radius * polarRadius * math.sin(polarAngleRad),
    );
  }

  @override
  String toString() {
    final signal = signalId == null ? '-' : signalId.toString();
    return 'SatelliteInfo($system PRN$prn elev=$elevation az=$azimuth snr=$snr signal=$signal band=$bandLabel)';
  }

  static GnssConstellation constellationFromTalker(String talkerId) {
    switch (talkerId) {
      case 'GP':
        return GnssConstellation.gps;
      case 'GL':
        return GnssConstellation.glonass;
      case 'GA':
        return GnssConstellation.galileo;
      case 'GB':
      case 'BD':
        return GnssConstellation.beidou;
      case 'GQ':
      case 'QZ':
        return GnssConstellation.qzss;
      case 'GI':
      case 'IN':
        return GnssConstellation.navic;
      case 'GN':
        return GnssConstellation.mixed;
      default:
        return GnssConstellation.unknown;
    }
  }

  static String _bandLabel(GnssConstellation constellation, int? signalId) {
    if (signalId == null) return 'Unknown';

    switch (constellation) {
      case GnssConstellation.gps:
        switch (signalId) {
          case 1:
            return 'L1 C/A';
          case 5:
            return 'L2C';
          case 6:
            return 'L5';
          default:
            return 'GPS sig $signalId';
        }

      case GnssConstellation.glonass:
        switch (signalId) {
          case 1:
            return 'G1';
          case 3:
            return 'G2';
          default:
            return 'GLO sig $signalId';
        }

      case GnssConstellation.galileo:
        switch (signalId) {
          case 1:
            return 'E1';
          case 6:
            return 'E5a';
          case 7:
            return 'E5b';
          case 8:
            return 'E5 AltBOC';
          default:
            return 'GAL sig $signalId';
        }

      case GnssConstellation.beidou:
        switch (signalId) {
          case 1:
            return 'B1I';
          case 3:
            return 'B2I';
          case 5:
            return 'B1C';
          case 7:
            return 'B2a';
          default:
            return 'BDS sig $signalId';
        }

      case GnssConstellation.qzss:
        switch (signalId) {
          case 1:
            return 'L1 C/A';
          case 4:
            return 'L1S';
          case 5:
            return 'L2C';
          case 6:
            return 'L5';
          default:
            return 'QZSS sig $signalId';
        }

      case GnssConstellation.sbas:
        switch (signalId) {
          case 1:
            return 'L1';
          case 6:
            return 'L5';
          default:
            return 'SBAS sig $signalId';
        }

      case GnssConstellation.navic:
        switch (signalId) {
          case 1:
            return 'L5';
          case 2:
            return 'S';
          default:
            return 'NavIC sig $signalId';
        }

      case GnssConstellation.mixed:
        return 'Mixed sig $signalId';

      case GnssConstellation.unknown:
        return 'Unknown';
    }
  }
}
