import 'dart:async';
import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:get/get.dart';

import '../pages/ntrip_settings/presentation/views/ntrip_settings_sheet.dart';
import '../services/gnss/gnss_connection.dart';
import '../services/gnss/gnss_device_service.dart';
import '../services/gnss/gnss_service.dart';
import '../services/ntrip_service.dart';

/// NTRIP állapotkártya — bottom sheet.
///
/// A mérnök két kérdésére válaszol:
///  1. „Jön a korrekció?"  → kapcsolat, KORREKCIÓ KORA (a legfontosabb
///     egészség-metrika: élő TCP mellett is kiderül, ha az adat elakadt),
///     adatforgalom, GGA-küldés.
///  2. „Lett belőle RTK fix?" → fix típusa + becsült hiba a GNSS oldalról.
///
/// Megnyitás: az appbar NTRIP-chipjére koppintva (NtripStatusSheet.show()).
class NtripStatusSheet extends StatefulWidget {
  const NtripStatusSheet({super.key});

  static Future<void> show() {
    return Get.bottomSheet(
      const NtripStatusSheet(),
      isScrollControlled: true,
    );
  }

  @override
  State<NtripStatusSheet> createState() => _NtripStatusSheetState();
}

class _NtripStatusSheetState extends State<NtripStatusSheet> {
  Timer? _ticker;
  bool _busy = false;

  @override
  void initState() {
    super.initState();
    // Másodpercenkénti frissítés a "korrekció kora" / időtartam számláláshoz.
    _ticker = Timer.periodic(const Duration(seconds: 1), (_) {
      if (mounted) setState(() {});
    });
  }

  @override
  void dispose() {
    _ticker?.cancel();
    super.dispose();
  }

  Future<void> _toggleConnection() async {
    final ntrip = NtripService.to;
    setState(() => _busy = true);
    try {
      if (ntrip.isConnected.value) {
        await ntrip.disconnect();
      } else {
        await ntrip.connect();
        Get.snackbar('NTRIP', 'Kapcsolódva: ${ntrip.mountpoint.value}',
            snackPosition: SnackPosition.BOTTOM,
            backgroundColor: const Color(0xFF2E7D32),
            colorText: const Color(0xFFFFFFFF));
      }
    } on NtripException catch (e) {
      Get.snackbar('NTRIP', e.message,
          snackPosition: SnackPosition.BOTTOM,
          backgroundColor: const Color(0xFFB71C1C),
          colorText: const Color(0xFFFFFFFF),
          duration: const Duration(seconds: 4));
    } catch (e) {
      Get.snackbar('NTRIP', e.toString(),
          snackPosition: SnackPosition.BOTTOM,
          backgroundColor: const Color(0xFFB71C1C),
          colorText: const Color(0xFFFFFFFF));
    } finally {
      if (mounted) setState(() => _busy = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    final colorScheme = Theme.of(context).colorScheme;

    return SafeArea(
      top: false,
      child: Material(
        color: colorScheme.surface,
        borderRadius: const BorderRadius.vertical(top: Radius.circular(24)),
        clipBehavior: Clip.antiAlias,
        child: Padding(
          padding: const EdgeInsets.fromLTRB(16, 12, 16, 16),
          child: Obx(() {
            final ntrip = NtripService.to;
            final connected = ntrip.isConnected.value;

            return Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                Center(
                  child: Container(
                    width: 42,
                    height: 4,
                    margin: const EdgeInsets.only(bottom: 14),
                    decoration: BoxDecoration(
                      color: colorScheme.outlineVariant,
                      borderRadius: BorderRadius.circular(999),
                    ),
                  ),
                ),

                // ── Fejléc: állapot + caster ────────────────────────
                Row(
                  children: [
                    Icon(Icons.cell_tower,
                        color: connected ? Colors.green : Colors.grey),
                    const SizedBox(width: 8),
                    Expanded(
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            connected
                                ? 'NTRIP kapcsolódva'
                                : 'NTRIP nincs kapcsolat',
                            style: Theme.of(context).textTheme.titleMedium,
                          ),
                          Text(
                            ntrip.hasCompleteSettings
                                ? '${ntrip.host.value} · ${ntrip.mountpoint.value}'
                                : 'Nincs beállítva',
                            style: TextStyle(
                                fontSize: 12, color: Colors.grey.shade600),
                          ),
                        ],
                      ),
                    ),
                    if (connected && ntrip.connectedSince.value != null)
                      Text(
                        _formatDuration(DateTime.now()
                            .difference(ntrip.connectedSince.value!)),
                        style: TextStyle(
                            fontSize: 12, color: Colors.grey.shade600),
                      ),
                  ],
                ),

                if (ntrip.lastError.value.isNotEmpty && !connected) ...[
                  const SizedBox(height: 8),
                  _ErrorBanner(text: ntrip.lastError.value),
                ],

                const SizedBox(height: 14),

                // ── Korrekció kora — a fő egészség-jelző ───────────
                _CorrectionAgeTile(
                  connected: connected,
                  lastRtcmAt: ntrip.lastRtcmAt.value,
                ),

                const SizedBox(height: 10),

                // ── Metrikák rácsban ───────────────────────────────
                Row(
                  children: [
                    Expanded(
                      child: _MetricTile(
                        label: 'Fogadott adat',
                        value: _formatBytes(ntrip.receivedBytes.value),
                        sub: '${ntrip.packetCount.value} csomag',
                      ),
                    ),
                    const SizedBox(width: 8),
                    Expanded(
                      child: _MetricTile(
                        label: 'GGA küldve',
                        value: '${ntrip.ggaSentCount.value} db',
                        sub: ntrip.ggaLastSentTime.value.isEmpty
                            ? 'még nem'
                            : 'utolsó: ${ntrip.ggaLastSentTime.value} UTC',
                        warn: connected && ntrip.ggaSentCount.value == 0,
                      ),
                    ),
                  ],
                ),

                const SizedBox(height: 10),

                // ── Eredmény: a GNSS oldal ─────────────────────────
                _FixResultTile(),

                const SizedBox(height: 16),

                // ── Gombok ─────────────────────────────────────────
                Row(
                  children: [
                    Expanded(
                      child: OutlinedButton.icon(
                        icon: const Icon(Icons.settings, size: 18),
                        label: const Text('Beállítások'),
                        onPressed: () {
                          Get.back();
                          NtripSettingsSheet.show();
                        },
                      ),
                    ),
                    const SizedBox(width: 12),
                    Expanded(
                      child: FilledButton.icon(
                        icon: _busy
                            ? const SizedBox(
                                width: 18,
                                height: 18,
                                child:
                                    CircularProgressIndicator(strokeWidth: 2),
                              )
                            : Icon(connected ? Icons.link_off : Icons.link,
                                size: 18),
                        label: Text(connected ? 'Bontás' : 'Kapcsolódás'),
                        style: connected
                            ? FilledButton.styleFrom(
                                backgroundColor: colorScheme.errorContainer,
                                foregroundColor: colorScheme.onErrorContainer,
                              )
                            : null,
                        onPressed: _busy ? null : _toggleConnection,
                      ),
                    ),
                  ],
                ),
              ],
            );
          }),
        ),
      ),
    );
  }
}

// ═════════════════════════════════════════════════════════════════════
// Rész-widgetek
// ═════════════════════════════════════════════════════════════════════

/// A korrekció kora, színkódolva: <2 s zöld, 2–10 s sárga, >10 s piros.
/// Ez mutatja meg azt az alattomos állapotot is, amikor a TCP-kapcsolat
/// él, de adat már nem jön (mobilnet-lyuk).
class _CorrectionAgeTile extends StatelessWidget {
  final bool connected;
  final DateTime? lastRtcmAt;
  const _CorrectionAgeTile({required this.connected, this.lastRtcmAt});

  @override
  Widget build(BuildContext context) {
    String text;
    String label = 'Korrekció kora';
    Color color;
    IconData icon;

    if (!connected) {
      text = '—';
      label = 'Korrekció';
      color = Colors.grey;
      icon = Icons.satellite_alt_outlined;
    } else if (lastRtcmAt == null) {
      text = 'várakozás az első csomagra…';
      color = Colors.orange;
      icon = Icons.hourglass_top;
    } else {
      final age = DateTime.now().difference(lastRtcmAt!);
      final s = age.inSeconds;
      text = s < 1 ? '<1 s' : '$s s';
      if (s < 2) {
        color = Colors.green;
        icon = Icons.check_circle;
      } else if (s <= 10) {
        color = Colors.orange;
        icon = Icons.warning_amber_rounded;
      } else {
        color = Colors.red;
        icon = Icons.error;
        label = 'Korrekció ELAVULT';
      }
    }

    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
      decoration: BoxDecoration(
        color: color.withOpacity(0.10),
        borderRadius: BorderRadius.circular(12),
        border: Border.all(color: color.withOpacity(0.4)),
      ),
      child: Row(
        children: [
          Icon(icon, color: color),
          const SizedBox(width: 10),
          Expanded(
            child: Text(label,
                style: const TextStyle(fontWeight: FontWeight.w600)),
          ),
          Text(
            text,
            style: TextStyle(
              fontWeight: FontWeight.w700,
              fontSize: 16,
              color: color,
              fontFeatures: const [FontFeature.tabularFigures()],
            ),
          ),
        ],
      ),
    );
  }
}

/// Fix-eredmény a GNSS oldalról: a kör bezárul — látszik, hogy a
/// korrekció ténylegesen "megfogant-e" (RTK fixed a cél).
class _FixResultTile extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Obx(() {
      if (!Get.isRegistered<GnssService>()) return const SizedBox.shrink();
      final gnss = GnssService.to;

      final receiverConnected =
          gnss.connectionState.value == GnssConnectionState.connected;
      final type = gnss.activeConnectionType.value;

      if (!receiverConnected) {
        return const _MetricTile(
          label: 'GNSS vevő',
          value: 'Nincs csatlakoztatva',
          sub: 'A korrekcióhoz külső vevő kell',
          warn: true,
        );
      }
      if (type == GnssConnectionType.phoneGps) {
        return const _MetricTile(
          label: 'GNSS forrás',
          value: 'Telefon GPS',
          sub: 'RTK korrekció fogadására nem képes',
          warn: true,
        );
      }

      final quality = gnss.gpsQuality.value;
      final (label, color, icon) = switch (quality) {
        4 => ('RTK FIXED', Colors.green, Icons.verified),
        5 => ('RTK FLOAT', Colors.orange, Icons.adjust),
        2 => ('DGPS', Colors.blue, Icons.gps_fixed),
        1 => ('GPS (önálló)', Colors.grey, Icons.gps_not_fixed),
        0 => ('Nincs fix', Colors.red, Icons.gps_off),
        _ => ('Fix: $quality', Colors.grey, Icons.gps_fixed),
      };

      final hErr = math.sqrt(math.pow(gnss.latitudeError.value, 2) +
          math.pow(gnss.longitudeError.value, 2));
      final errText = hErr > 0
          ? '±${hErr < 1 ? '${(hErr * 100).toStringAsFixed(0)} cm' : '${hErr.toStringAsFixed(2)} m'} vízszintes'
          : 'HDOP: ${gnss.hdop.value.toStringAsFixed(1)}';

      return Container(
        padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
        decoration: BoxDecoration(
          color: color.withOpacity(0.10),
          borderRadius: BorderRadius.circular(12),
          border: Border.all(color: color.withOpacity(0.4)),
        ),
        child: Row(
          children: [
            Icon(icon, color: color),
            const SizedBox(width: 10),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(label,
                      style:
                          TextStyle(fontWeight: FontWeight.w700, color: color)),
                  Text(
                    '$errText · ${gnss.gsaUsedSatelliteCount.value} műhold',
                    style: TextStyle(fontSize: 12, color: Colors.grey.shade700),
                  ),
                ],
              ),
            ),
          ],
        ),
      );
    });
  }
}

class _MetricTile extends StatelessWidget {
  final String label;
  final String value;
  final String sub;
  final bool warn;
  const _MetricTile({
    required this.label,
    required this.value,
    required this.sub,
    this.warn = false,
  });

  @override
  Widget build(BuildContext context) {
    final color = warn ? Colors.orange : Colors.grey;
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
      decoration: BoxDecoration(
        color: Theme.of(context).colorScheme.surfaceContainerHighest,
        borderRadius: BorderRadius.circular(12),
        border: warn ? Border.all(color: Colors.orange.withOpacity(0.5)) : null,
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(label,
              style: TextStyle(fontSize: 11, color: Colors.grey.shade600)),
          const SizedBox(height: 2),
          Text(value,
              style: TextStyle(
                fontWeight: FontWeight.w700,
                color: warn ? Colors.orange.shade800 : null,
                fontFeatures: const [FontFeature.tabularFigures()],
              )),
          Text(sub,
              style: TextStyle(fontSize: 11, color: color.withOpacity(0.9))),
        ],
      ),
    );
  }
}

class _ErrorBanner extends StatelessWidget {
  final String text;
  const _ErrorBanner({required this.text});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      decoration: BoxDecoration(
        color: Colors.red.withOpacity(0.08),
        borderRadius: BorderRadius.circular(10),
      ),
      child: Row(
        children: [
          const Icon(Icons.error_outline, size: 16, color: Colors.red),
          const SizedBox(width: 8),
          Expanded(
            child: Text(text,
                style: const TextStyle(fontSize: 12, color: Colors.red)),
          ),
        ],
      ),
    );
  }
}

String _formatDuration(Duration d) {
  final h = d.inHours;
  final m = d.inMinutes % 60;
  final s = d.inSeconds % 60;
  if (h > 0) return '$h ó $m p';
  if (m > 0) return '$m:${s.toString().padLeft(2, '0')}';
  return '$s s';
}

String _formatBytes(int bytes) {
  if (bytes < 1024) return '$bytes B';
  if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)} KB';
  return '${(bytes / 1024 / 1024).toStringAsFixed(2)} MB';
}
