import 'dart:developer' as developer;

import 'package:flutter/foundation.dart';
import 'package:adjust_sdk/adjust.dart';
import 'package:adjust_sdk/adjust_attribution.dart';
import 'package:adjust_sdk/adjust_config.dart';
import 'package:adjust_sdk/adjust_event.dart';
import 'package:adjust_sdk/adjust_event_failure.dart';
import 'package:adjust_sdk/adjust_event_success.dart';
import 'package:adjust_sdk/adjust_session_failure.dart';
import 'package:adjust_sdk/adjust_session_success.dart';

import '../utils/report.dart';


typedef EventParams = Map<String, dynamic>;

class AdjustService {
  Map<String, String> _eventNameToToken = {};
  Map<String, String> get eventNameToToken => _eventNameToToken;
  set eventNameToToken(Map<String, String> m) {
    _eventNameToToken = Map<String, String>.from(m);
  }

  AdjustService._();

  static final AdjustService instance = AdjustService._();

  bool _inited = false;

  String _toStr(dynamic v) => '$v';

  double? _toNum(dynamic v) {
    if (v == null) return null;
    if (v is num) return v.toDouble();
    return double.tryParse('$v');
  }

  Future<void> init(String appToken, [bool isProd = true]) async {
    developer.log(appToken, name: 'Adjust');

    if (_inited) {
      developer.log('[Adjust] already inited', name: 'Adjust');
      return;
    }

    if (appToken.isEmpty) return;

    final environment = isProd
        ? AdjustEnvironment.production
        : AdjustEnvironment.sandbox;

    final config = AdjustConfig(appToken, environment);

    config.isCostDataInAttributionEnabled = true;

    config.attributionCallback = (AdjustAttribution a) async {
      debugPrint('Adjust attribution: ${a.toString()}');
      ReportService.I.attribution = a;
      ReportService.I.reportAttribution();
    };
    config.eventSuccessCallback = (AdjustEventSuccess s) {
      debugPrint('Adjust event success: ${s.toString()}');
    };
    config.eventFailureCallback = (AdjustEventFailure f) {
      debugPrint('Adjust event failure: ${f.toString()}');
    };
    config.sessionSuccessCallback = (AdjustSessionSuccess s) {
      debugPrint('Adjust session success: ${s.toString()}');
    };
    config.sessionFailureCallback = (AdjustSessionFailure f) {
      debugPrint('Adjust session failure: ${f.toString()}');
    };

    // 可选：如果你希望缓存更多 deduplicationId，可调大
    config.eventDeduplicationIdsMaxSize = 20;

    config.logLevel = isProd ? AdjustLogLevel.info : AdjustLogLevel.verbose;

    Adjust.initSdk(config);
    _inited = true;
  }

  Future<void> trackEventWithName(
    String eventName, [
    EventParams? params,
  ]) async {
    debugPrint('call trackEventWithName eventName $eventName params $params');
    // 你可以在这里做个映射，eventName -> eventToken
    // 也可以直接让外部传 eventToken 过来
    ReportService.I.report(eventName, params);
  

    final eventToken = _eventNameToToken[eventName];
    if (eventToken == null) {
      debugPrint('not find eventToken $eventName');
      return;
    }

    await trackEvent(eventToken, params);
  }

  Future<void> trackEvent(String eventToken, [EventParams? params]) async {
    try {
      debugPrint("track event eventToken $eventToken params $params");
      if (eventToken.isEmpty) return;

      final event = AdjustEvent(eventToken);

      if (params != null && params.isNotEmpty) {
        double? revenue;
        String? currency;

        // 优先级：deduplicationId > orderId > transactionId
        String? dedupId;

        for (final entry in params.entries) {
          final key = entry.key;
          final value = entry.value;

          if (value == null) continue;

          switch (key) {
            case 'revenue':
            case 'amount':
              revenue = _toNum(value);
              break;

            case 'currency':
              currency = _toStr(value);
              break;

            case 'deduplicationId':
            case 'orderId':
              dedupId ??= _toStr(value);
              break;

            case 'callbackId':
              event.callbackId = _toStr(value);
              break;

            case 'transactionId':
              final tid = _toStr(value);
              event.transactionId = tid;
              dedupId ??= tid;
              break;

            case 'productId':
              event.productId = _toStr(value);
              break;

            case 'purchaseToken':
              event.purchaseToken = _toStr(value);
              break;
            default:
              final v = _toStr(value);

              if (key.startsWith('partner:')) {
                final realKey = key.substring('partner:'.length);
                if (realKey.isNotEmpty) {
                  event.addPartnerParameter(realKey, v);
                }
              } else {
                event.addCallbackParameter(key, v);
              }
              break;
          }
        }

        if (dedupId != null && dedupId.isNotEmpty) {
          event.deduplicationId = dedupId;
        }

        if (revenue != null && currency != null && currency.isNotEmpty) {
          event.setRevenue(revenue, currency);
        }
      }

      Adjust.trackEvent(event);
    } catch (e, st) {
      developer.log(
        '[Adjust] trackEvent error: $e',
        name: 'Adjust',
        stackTrace: st,
      );
    }
  }
}
