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

import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:pointycastle/export.dart' as pc;
import 'package:pointycastle/asn1/asn1_parser.dart';
import 'package:pointycastle/asn1/primitives/asn1_bit_string.dart';
import 'package:pointycastle/asn1/primitives/asn1_integer.dart';
import 'package:pointycastle/asn1/primitives/asn1_sequence.dart';

import 'package:asciineverdie/data/game_text_l10n.dart' as game_l10n;

/// IAP 상품 ID
class IAPProductIds {
  IAPProductIds._();

  /// 광고 제거 상품 ID (비소모성)
  static const String removeAds = 'remove_ads_and';

  /// 모든 상품 ID 목록
  static const Set<String> all = {removeAds};
}

/// IAP 구매 결과
enum IAPResult {
  /// 구매 성공
  success,

  /// 구매 취소
  cancelled,

  /// 구매 실패
  failed,

  /// 이미 구매됨
  alreadyPurchased,

  /// 상품을 찾을 수 없음
  productNotFound,

  /// 스토어 사용 불가
  storeUnavailable,

  /// 디버그 모드에서 시뮬레이션
  debugSimulated,
}

/// Google Play 공개키 (public key)
///
/// Google Play Console > 수익 창출(Monetization) 설정 > 라이선스(Licensing)에서
/// Base64 인코딩된 RSA 공개키를 복사하여 아래에 붙여넣기.
/// 공개키이므로 비밀이 아니지만, 바이너리 스캔 방지를 위해 분할 저장.
const _gpKeyPart1 = 'YOUR_GOOGLE_PLAY_';
const _gpKeyPart2 = 'PUBLIC_KEY_HERE';
String get _googlePlayPublicKey => _gpKeyPart1 + _gpKeyPart2;

/// IAP 서비스
///
/// 인앱 구매 (광고 제거) 처리를 담당합니다.
/// flutter_secure_storage를 사용하여 구매 상태를 보안 저장합니다.
class IAPService {
  IAPService._();

  static IAPService? _instance;

  /// 싱글톤 인스턴스
  static IAPService get instance {
    _instance ??= IAPService._();
    return _instance!;
  }

  // ===========================================================================
  // 상수
  // ===========================================================================

  /// 구매 상태 저장 키
  static const String _purchaseKey = 'iap_remove_ads_purchased';

  /// 보안 저장소 (secure storage) 인스턴스
  static const FlutterSecureStorage _secureStorage = FlutterSecureStorage();

  // ===========================================================================
  // 상태
  // ===========================================================================

  late final InAppPurchase _iap = InAppPurchase.instance;

  bool _isInitialized = false;
  bool _isAvailable = false;

  /// 상품 정보
  ProductDetails? _removeAdsProduct;

  /// 구매 스트림 구독
  StreamSubscription<List<PurchaseDetails>>? _subscription;

  /// 광고 제거 구매 여부 (캐시)
  bool _adRemovalPurchased = false;

  /// 디버그 모드에서 IAP 시뮬레이션 활성화 여부
  bool _debugIAPSimulated = false;

  // ===========================================================================
  // 초기화
  // ===========================================================================

  /// IAP 서비스 초기화
  Future<void> initialize() async {
    if (_isInitialized) return;

    // 모바일 플랫폼에서만 초기화
    if (!Platform.isAndroid && !Platform.isIOS) {
      debugPrint('[IAPService] Non-mobile platform, skipping initialization');
      return;
    }

    // 저장된 구매 상태 로드
    await _loadPurchaseState();

    // 스토어 가용성 확인
    _isAvailable = await _iap.isAvailable();
    if (!_isAvailable) {
      debugPrint('[IAPService] Store not available');
      _isInitialized = true;
      return;
    }

    // 구매 스트림 구독
    _subscription = _iap.purchaseStream.listen(
      _onPurchaseUpdate,
      onError: (Object error) {
        debugPrint('[IAPService] Purchase stream error: $error');
      },
    );

    // 상품 정보 로드
    await _loadProducts();

    _isInitialized = true;
    debugPrint('[IAPService] Initialized');

    // 로컬에 구매 기록이 없으면 스토어에서 자동 복원 시도
    // (앱 삭제 후 재설치 대응, 비동기로 실행하여 초기화 블로킹 없음)
    if (!_adRemovalPurchased) {
      _tryAutoRestore();
    }
  }

  /// 상품 정보 로드
  Future<void> _loadProducts() async {
    final response = await _iap.queryProductDetails(IAPProductIds.all);

    if (response.notFoundIDs.isNotEmpty) {
      debugPrint('[IAPService] Products not found: ${response.notFoundIDs}');
    }

    for (final product in response.productDetails) {
      if (product.id == IAPProductIds.removeAds) {
        _removeAdsProduct = product;
        debugPrint(
          '[IAPService] Product loaded: ${product.id} - ${product.price}',
        );
      }
    }
  }

  /// 앱 시작 시 자동 구매 복원 (재설치 대응)
  ///
  /// purchaseStream 구독 후 호출되므로, 복원된 구매는
  /// _onPurchaseUpdate → _handleSuccessfulPurchase로 처리됨.
  void _tryAutoRestore() {
    debugPrint('[IAPService] Attempting auto-restore...');
    _iap.restorePurchases().catchError((Object error) {
      debugPrint('[IAPService] Auto-restore failed: $error');
    });
  }

  /// 저장된 구매 상태 로드 (보안 저장소 사용)
  Future<void> _loadPurchaseState() async {
    final value = await _secureStorage.read(key: _purchaseKey);
    _adRemovalPurchased = value == 'true';
    debugPrint('[IAPService] Loaded purchase state: $_adRemovalPurchased');
  }

  /// 구매 상태 저장 (보안 저장소 사용)
  Future<void> _savePurchaseState(bool purchased) async {
    await _secureStorage.write(
      key: _purchaseKey,
      value: purchased.toString(),
    );
    _adRemovalPurchased = purchased;
    debugPrint('[IAPService] Saved purchase state: $purchased');
  }

  // ===========================================================================
  // 디버그 설정
  // ===========================================================================

  /// 디버그 모드 IAP 시뮬레이션 활성화 여부
  bool get debugIAPSimulated => _debugIAPSimulated;

  /// 디버그 모드 IAP 시뮬레이션 토글
  set debugIAPSimulated(bool value) {
    _debugIAPSimulated = value;
    if (kDebugMode) {
      _adRemovalPurchased = value;
      debugPrint('[IAPService] Debug IAP simulated: $value');
    }
  }

  // ===========================================================================
  // 구매 상태
  // ===========================================================================

  /// 광고 제거 구매 여부
  bool get isAdRemovalPurchased {
    if (kDebugMode && _debugIAPSimulated) return true;
    return _adRemovalPurchased;
  }

  /// 스토어 가용성
  bool get isStoreAvailable => _isAvailable;

  /// 광고 제거 상품 정보
  ProductDetails? get removeAdsProduct => _removeAdsProduct;

  /// 광고 제거 상품 가격 문자열
  String get removeAdsPrice {
    if (_removeAdsProduct != null) {
      return _removeAdsProduct!.price;
    }
    // 스토어 미연결 시 로케일별 대체 가격
    return switch (game_l10n.currentGameLocale) {
      'ko' => '₩9,900',
      'ja' => '¥990',
      _ => '\$9.99',
    };
  }

  // ===========================================================================
  // 구매
  // ===========================================================================

  /// 광고 제거 구매
  Future<IAPResult> purchaseRemoveAds() async {
    // 디버그 모드 시뮬레이션
    if (kDebugMode && _debugIAPSimulated) {
      debugPrint('[IAPService] Debug: Simulating purchase');
      await _savePurchaseState(true);
      return IAPResult.debugSimulated;
    }

    // 이미 구매됨
    if (_adRemovalPurchased) {
      debugPrint('[IAPService] Already purchased');
      return IAPResult.alreadyPurchased;
    }

    // 스토어 사용 불가
    if (!_isAvailable) {
      debugPrint('[IAPService] Store not available');
      return IAPResult.storeUnavailable;
    }

    // 상품을 찾을 수 없음
    if (_removeAdsProduct == null) {
      debugPrint('[IAPService] Product not found');
      return IAPResult.productNotFound;
    }

    // 구매 요청
    final purchaseParam = PurchaseParam(productDetails: _removeAdsProduct!);

    try {
      final success = await _iap.buyNonConsumable(purchaseParam: purchaseParam);
      debugPrint('[IAPService] Purchase initiated: $success');
      return success ? IAPResult.success : IAPResult.failed;
    } catch (e) {
      debugPrint('[IAPService] Purchase error: $e');
      return IAPResult.failed;
    }
  }

  // ===========================================================================
  // 구매 복원
  // ===========================================================================

  /// 구매 복원
  Future<IAPResult> restorePurchases() async {
    // 디버그 모드 시뮬레이션
    if (kDebugMode && _debugIAPSimulated) {
      debugPrint('[IAPService] Debug: Simulating restore');
      await _savePurchaseState(true);
      return IAPResult.debugSimulated;
    }

    // 스토어 사용 불가
    if (!_isAvailable) {
      debugPrint('[IAPService] Store not available');
      return IAPResult.storeUnavailable;
    }

    try {
      await _iap.restorePurchases();
      debugPrint('[IAPService] Restore initiated');
      return IAPResult.success;
    } catch (e) {
      debugPrint('[IAPService] Restore error: $e');
      return IAPResult.failed;
    }
  }

  // ===========================================================================
  // 구매 처리
  // ===========================================================================

  /// 구매 업데이트 처리
  void _onPurchaseUpdate(List<PurchaseDetails> purchases) {
    for (final purchase in purchases) {
      debugPrint(
        '[IAPService] Purchase update: ${purchase.productID} - '
        '${purchase.status}',
      );

      switch (purchase.status) {
        case PurchaseStatus.pending:
          // 구매 대기 중
          debugPrint('[IAPService] Purchase pending');

        case PurchaseStatus.purchased:
        case PurchaseStatus.restored:
          // 구매 완료 또는 복원
          _handleSuccessfulPurchase(purchase);

        case PurchaseStatus.error:
          // 구매 실패
          debugPrint('[IAPService] Purchase error: ${purchase.error}');
          _completePurchase(purchase);

        case PurchaseStatus.canceled:
          // 구매 취소
          debugPrint('[IAPService] Purchase canceled');
          _completePurchase(purchase);
      }
    }
  }

  /// 구매 성공 처리 (서명 검증 포함)
  Future<void> _handleSuccessfulPurchase(PurchaseDetails purchase) async {
    if (purchase.productID == IAPProductIds.removeAds) {
      // 플랫폼별 로컬 영수증 검증 (local receipt verification)
      final verified = _verifyPurchaseLocally(purchase);
      if (!verified) {
        debugPrint('[IAPService] Purchase verification FAILED - not granting');
        await _completePurchase(purchase);
        return;
      }

      await _savePurchaseState(true);
      debugPrint('[IAPService] Ad removal purchased & verified successfully');
    }

    // 구매 완료 처리
    await _completePurchase(purchase);
  }

  // ===========================================================================
  // 로컬 영수증 검증 (local receipt verification)
  // ===========================================================================

  /// 플랫폼별 로컬 구매 검증
  ///
  /// Google Play: RSASSA-PKCS1-v1_5 + SHA1 서명 검증
  /// Apple: StoreKit 2 플러그인 자체 검증 (향후 JWS 로컬 검증 추가 예정)
  bool _verifyPurchaseLocally(PurchaseDetails purchase) {
    final source = purchase.verificationData.source;

    if (source == 'google_play') {
      return _verifyGooglePlayPurchase(purchase);
    } else if (source == 'app_store') {
      // TODO: Apple StoreKit 2 JWS 로컬 검증 추가
      // 현재는 in_app_purchase 플러그인의 네이티브 검증에 의존
      debugPrint('[IAPService] Apple purchase - plugin-native verification');
      return true;
    }

    debugPrint('[IAPService] Unknown source: $source - skipping verification');
    return true;
  }

  /// Google Play 구매 RSA 서명 검증
  ///
  /// localVerificationData는 Base64 인코딩된 서명 JSON 데이터.
  /// serverVerificationData에 원본 구매 JSON이 포함됨.
  bool _verifyGooglePlayPurchase(PurchaseDetails purchase) {
    try {
      final signedData = purchase.verificationData.serverVerificationData;
      final signature = purchase.verificationData.localVerificationData;

      if (signedData.isEmpty || signature.isEmpty) {
        debugPrint('[IAPService] Empty verification data');
        return false;
      }

      return _verifyRsaSignature(signedData, signature, _googlePlayPublicKey);
    } catch (e) {
      debugPrint('[IAPService] Google Play verification error: $e');
      return false;
    }
  }

  /// RSASSA-PKCS1-v1_5 + SHA1 서명 검증
  ///
  /// Google Play 서명 검증에 사용되는 RSA 알고리즘.
  /// [data]: 서명된 원본 데이터 (signed data)
  /// [signatureBase64]: Base64 인코딩된 서명 (signature)
  /// [publicKeyBase64]: Base64 인코딩된 DER 공개키 (public key)
  bool _verifyRsaSignature(
    String data,
    String signatureBase64,
    String publicKeyBase64,
  ) {
    try {
      // 공개키 DER 바이트 디코딩 (decode public key)
      final publicKeyBytes = base64Decode(publicKeyBase64);
      final publicKey = _parsePublicKeyFromDer(publicKeyBytes);

      // 서명 디코딩 (decode signature)
      final signatureBytes = base64Decode(signatureBase64);

      // 원본 데이터를 UTF-8 바이트로 변환
      final dataBytes = Uint8List.fromList(utf8.encode(data));

      // RSASSA-PKCS1-v1_5 + SHA1 검증
      final signer = pc.Signer('SHA-1/RSA');
      signer.init(
        false, // verify 모드
        pc.PublicKeyParameter<pc.RSAPublicKey>(publicKey),
      );

      return signer.verifySignature(
        dataBytes,
        pc.RSASignature(signatureBytes),
      );
    } catch (e) {
      debugPrint('[IAPService] RSA verification error: $e');
      return false;
    }
  }

  /// DER 인코딩된 공개키 파싱 (parse DER-encoded public key)
  ///
  /// X.509 SubjectPublicKeyInfo 형식의 DER 바이트에서 RSA 공개키 추출.
  pc.RSAPublicKey _parsePublicKeyFromDer(Uint8List bytes) {
    // ASN.1 시퀀스 파서 (ASN.1 sequence parser)
    final asn1Parser = ASN1Parser(bytes);
    final topSequence = asn1Parser.nextObject() as ASN1Sequence;

    // SubjectPublicKeyInfo 내부의 BitString에서 공개키 추출
    final bitString = topSequence.elements![1] as ASN1BitString;
    final publicKeyBytes = bitString.stringValues as Uint8List;

    // RSA 공개키 시퀀스 파싱
    final rsaParser = ASN1Parser(publicKeyBytes);
    final rsaSequence = rsaParser.nextObject() as ASN1Sequence;

    final modulus =
        (rsaSequence.elements![0] as ASN1Integer).integer!;
    final exponent =
        (rsaSequence.elements![1] as ASN1Integer).integer!;

    return pc.RSAPublicKey(modulus, exponent);
  }

  /// 구매 완료 처리 (필수)
  Future<void> _completePurchase(PurchaseDetails purchase) async {
    if (purchase.pendingCompletePurchase) {
      await _iap.completePurchase(purchase);
      debugPrint('[IAPService] Purchase completed: ${purchase.productID}');
    }
  }

  // ===========================================================================
  // 정리
  // ===========================================================================

  /// 리소스 해제
  void dispose() {
    _subscription?.cancel();
    _subscription = null;
    debugPrint('[IAPService] Disposed');
  }
}
