// SPDX-License-Identifier: Proprietary
// Service d'attestation d'intégrité de l'appareil (Play Integrity Android + App Attest iOS).
//
// Obligatoire pour audit BCEAO PI-SPI (banking-grade). Permet au backend de vérifier que :
//   - L'app n'a pas été modifiée (signature intacte)
//   - L'appareil n'est pas root/jailbreak (en complément de freeRASP)
//   - L'app provient bien d'un store officiel (Play Store / App Store)
//   - Aucun debugger n'est attaché
//
// Le token retourné doit être envoyé au backend (header `X-Device-Integrity-Token`) et
// vérifié serveur-side via les API Google/Apple.
//
// @since 2026-04-25 (P0-NEW-22)

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

import '../utils/app_logger.dart';

class AppDeviceIntegrityService {
  AppDeviceIntegrityService._();

  static final AppDeviceIntegrityService instance =
      AppDeviceIntegrityService._();

  /// Cloud Project Number (Android) — à renseigner depuis env (--dart-define=GCP_PROJECT_NUMBER=...).
  static const String _gcpProjectNumber =
      String.fromEnvironment('GCP_PROJECT_NUMBER', defaultValue: '');

  /// Token cache (court — 1 minute max). Chaque requête sensible doit redemander un nouveau token.
  String? _cachedToken;
  DateTime? _cachedAt;

  /// Demande un token d'attestation d'intégrité fraîche.
  ///
  /// [challenge] : nonce/challenge unique fourni par le backend pour éviter les replay attacks.
  /// Idéalement, le backend génère un challenge aléatoire à chaque requête sensible et le retourne
  /// dans la réponse précédente.
  ///
  /// Retourne null si l'attestation échoue (mode dégradé — à logger côté backend).
  Future<String?> requestToken(String challenge) async {
    if (kDebugMode) {
      AppLogger.warning(
          'AppDeviceIntegrity: mode debug → bypass attestation (token=null)',
          tag: 'AppIntegrity');
      return null;
    }

    // Cache 60s pour éviter de spammer Google/Apple
    if (_cachedToken != null && _cachedAt != null) {
      final age = DateTime.now().difference(_cachedAt!).inSeconds;
      if (age < 60) {
        return _cachedToken;
      }
    }

    try {
      final integrity = AppDeviceIntegrity();
      final String? token = await integrity.getAttestationServiceSupport(
        challengeString: challenge,
        gcpProjectNumber: _gcpProjectNumber.isNotEmpty
            ? int.parse(_gcpProjectNumber)
            : 0,
      );

      if (token == null || token.isEmpty) {
        AppLogger.error(
            'AppDeviceIntegrity: token vide reçu — attestation échouée',
            tag: 'AppIntegrity');
        return null;
      }

      _cachedToken = token;
      _cachedAt = DateTime.now();
      AppLogger.info(
          'AppDeviceIntegrity: token attestation obtenu (${token.length} chars)',
          tag: 'AppIntegrity');
      return token;
    } catch (e, st) {
      AppLogger.error(
          'AppDeviceIntegrity: échec attestation : $e',
          tag: 'AppIntegrity',
          error: e,
          stackTrace: st);
      return null;
    }
  }

  /// Invalide le cache (à appeler sur logout ou changement de compte).
  void invalidateCache() {
    _cachedToken = null;
    _cachedAt = null;
  }
}
