import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:device_info_plus/device_info_plus.dart';
import 'package:package_info_plus/package_info_plus.dart';

import '../../../../push/push_registration_store.dart';
import '../../../../push/push_registration_type.dart';
import '../../marianumconnect_query.dart';
import 'telemetry_device_id.dart';

/// Sends a telemetry heartbeat to MarianumConnect (`POST me/telemetry`) —
/// upserts the stable install id, platform, app version and device info. Sent
/// on app start, again once push registration completes that session (so a
/// fresh registration isn't under-reported until the next launch), and on
/// resume after the app spent more than 15 minutes in the background.
/// Bearer-authenticated via the shared dio interceptor. Replaces the legacy
/// mhsl.eu `server/userIndex/update` call.
class TelemetryHeartbeat extends MarianumConnectQuery {
  TelemetryHeartbeat({super.dio});

  /// Fire-and-forget: schedules a heartbeat and swallows any error, so a failed
  /// send never disrupts app start. Used from the app shell's initState and
  /// lifecycle handler, and re-emitted once push registration completes (see
  /// `_MainState._syncPush`).
  static void report({required bool notificationsEnabled}) {
    unawaited(
      TelemetryHeartbeat()
          .send(notificationsEnabled: notificationsEnabled)
          .catchError((Object _) {}),
    );
  }

  Future<void> send({required bool notificationsEnabled}) => guard(() async {
    final info = DeviceInfoPlugin();
    final package = await PackageInfo.fromPlatform();
    final deviceIdentifier = await TelemetryDeviceId.resolve();
    final pushDeviceIdentifier = await const PushRegistrationStore()
        .deviceIdentifier(PushRegistrationType.general);

    var platform = 'unknown';
    String? deviceModel;
    String? osVersion;
    var raw = <String, dynamic>{};
    if (Platform.isAndroid) {
      platform = 'android';
      final androidInfo = await info.androidInfo;
      deviceModel = androidInfo.model;
      osVersion = androidInfo.version.release;
      raw = androidInfo.data;
    } else if (Platform.isIOS) {
      platform = 'ios';
      final appleInfo = await info.iosInfo;
      deviceModel = appleInfo.utsname.machine;
      osVersion = appleInfo.systemVersion;
      raw = appleInfo.data;
    }

    await dio.post<void>(
      endpoint('me/telemetry'),
      data: {
        'deviceIdentifier': deviceIdentifier,
        // `pushDeviceIdentifier` reflects a *completed* registration and is
        // absent until it lands; `pushEnabled` carries the user's intent
        // (the notification toggle) so the backend can tell "user wants push"
        // apart from "registration not finished yet".
        'pushDeviceIdentifier': ?pushDeviceIdentifier,
        'pushEnabled': notificationsEnabled,
        'platform': platform,
        'appVersion': package.version,
        'appBuild': int.tryParse(package.buildNumber),
        'deviceModel': deviceModel,
        'osVersion': osVersion,
        'deviceInfo': jsonEncode(raw),
      },
    );
  });
}
