import 'dart:async';
import 'dart:developer';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:package_info_plus/package_info_plus.dart';

import 'report_client_error.dart';

/// Fire-and-forget bridge from the app's global error handlers to the
/// MarianumConnect `client-errors` endpoint.
///
/// A Flutter layout error (e.g. a RenderFlex overflow) re-fires on every frame,
/// so reports are deduplicated per session by a digit-normalized key — matching
/// the server-side fingerprint — and the number of distinct reports per session
/// is capped, so a broken screen produces one report, not thousands.
class ClientErrorReporter {
  static const int _maxReportsPerSession = 50;
  static final Set<String> _seen = {};
  static String? _appVersion;

  static void reportFlutterError(FlutterErrorDetails details) {
    _report(
      errorType: 'flutter',
      message: details.exceptionAsString(),
      stacktrace: details.stack?.toString(),
      context: details.library ?? details.context?.toString(),
    );
  }

  static void reportPlatformError(Object error, StackTrace stack) {
    _report(
      errorType: 'platform',
      message: error.toString(),
      stacktrace: stack.toString(),
    );
  }

  static void _report({
    required String errorType,
    required String message,
    String? stacktrace,
    String? context,
  }) {
    final key = _dedupKey(errorType, message, context);
    if (_seen.contains(key) || _seen.length >= _maxReportsPerSession) return;
    _seen.add(key);
    unawaited(_send(errorType, message, stacktrace, context));
  }

  static Future<void> _send(
    String errorType,
    String message,
    String? stacktrace,
    String? context,
  ) async {
    try {
      _appVersion ??= (await PackageInfo.fromPlatform()).version;
      await ReportClientError().run(
        errorType: errorType,
        message: message,
        stacktrace: stacktrace,
        context: context,
        platform: _platform(),
        appVersion: _appVersion,
      );
    } catch (e) {
      log('Client error report failed: $e');
    }
  }

  static String _dedupKey(String errorType, String message, String? context) {
    final normalized = message.toLowerCase().replaceAll(RegExp(r'\d+'), '#');
    return '$errorType|$normalized|${context ?? ''}';
  }

  static String? _platform() {
    if (Platform.isAndroid) return 'android';
    if (Platform.isIOS) return 'ios';
    return null;
  }
}
