import 'package:amplitude_flutter/amplitude.dart';
import 'package:amplitude_flutter/configuration.dart';
import 'package:amplitude_flutter/constants.dart' as amp;
import 'package:amplitude_flutter/events/base_event.dart';
import 'package:flutter/widgets.dart';
import 'package:pshared/models/account/account.dart';
import 'package:pshared/models/payment/type.dart';
import 'package:pshared/models/recipient/status.dart';
import 'package:pshared/models/recipient/type.dart';
import 'package:pweb/widgets/sidebar/destinations.dart';


class AmplitudeService {
  static late Amplitude _analytics;

  static Amplitude _amp() => _analytics;

  static Future<void> initialize() async {
    _analytics = Amplitude(Configuration(
      apiKey: '12345', //TODO define through App Contants
      serverZone: amp.ServerZone.eu, //TODO define through App Contants
    ));
    await _analytics.isBuilt;
  }

  static Future<void> identify(Account account) async =>
      _amp().setUserId(account.id);

  
  static Future<void> login(Account account) async =>
      _logEvent(
        'login',
        userProperties: {
          // 'email': account.email, TODO Add email into account
          'locale': account.locale,
        },
      );

  static Future<void> logout() async => _logEvent("logout");

  static Future<void> pageOpened(PayoutDestination page, {String? path, String? uiSource}) async {
    return _logEvent("pageOpened", eventProperties: {
      "page": page,
      if (path != null) "path": path,
      if (uiSource != null) "uiSource": uiSource,
    });
  }

  //TODO Add when registration is ready. User properties {user_id, registration_date, has_wallet (true/false), wallet_balance (should concider loggin it as: 0 / <100 / 100–500 / 500+), preferred_method (Wallet/Card/Bank/IBAN), total_transactions, total_amount, last_payout_date, last_login_date , marketing_source}
  
  // static Future<void> registrationStarted(String method, String country) async =>
  //   _logEvent("registrationStarted", eventProperties: {"method": method, "country": country});

  // static Future<void> registrationCompleted(String method, String country) async =>
  //     _logEvent("registrationCompleted", eventProperties: {"method": method, "country": country});

  static Future<void> pageNotFound(String url) async =>
      _logEvent("pageNotFound", eventProperties: {"url": url});

  static Future<void> localeChanged(Locale locale) async =>
      _logEvent("localeChanged", eventProperties: {"locale": locale.toString()});

  static Future<void> localeMatched(String locale, bool haveRequested) async => //DO we need it?
      _logEvent("localeMatched", eventProperties: {
        "locale": locale,
        "have_requested_locale": haveRequested
      });

  static Future<void> recipientAddStarted() async =>
      _logEvent("recipientAddStarted");

  static Future<void> recipientAddCompleted(
    RecipientType type, 
    RecipientStatus status, 
    Set<PaymentType> methods,
  ) async {
    _logEvent(
      "recipientAddCompleted", 
      eventProperties: {
        "methods": methods.map((m) => m.name).toList(),
        "type": type.name,
        "status": status.name,
      },
    );
  }

  static Future<void> _paymentEvent(
    String evt,
    double amount,
    double fee,
    bool payerCoversFee,
    PaymentType source,
    PaymentType recpientPaymentMethod, {
    String? message,
    String? errorType,
    Map<String, dynamic>? extraProps,
  }) async {
    final props = {
      "amount": amount,
      "fee": fee,
      "feeCoveredBy": payerCoversFee ? 'payer' : 'recipient',
      "source": source,
      "recipient_method": recpientPaymentMethod,
      if (message != null) "message": message,
      if (errorType != null) "error_type": errorType,
      if (extraProps != null) ...extraProps,
    };
    return _logEvent(evt, eventProperties: props);
  }

  static Future<void> paymentPrepared(double amount, double fee,
          bool payerCoversFee, PaymentType source, PaymentType recpientPaymentMethod) async =>
      _paymentEvent("paymentPrepared", amount, fee, payerCoversFee, source, recpientPaymentMethod);
  //TODO Rework paymentStarted (do i need all those properties or is the event enough? Mb properties should be passed at paymentPrepared)
  static Future<void> paymentStarted(double amount, double fee,
          bool payerCoversFee, PaymentType source, PaymentType recpientPaymentMethod) async =>
      _paymentEvent("paymentStarted", amount, fee, payerCoversFee, source, recpientPaymentMethod);

  static Future<void> paymentFailed(double amount, double fee, bool payerCoversFee,
      PaymentType source, PaymentType recpientPaymentMethod, String errorType, String message) async =>
      _paymentEvent("paymentFailed", amount, fee, payerCoversFee, source, recpientPaymentMethod,
          errorType: errorType, message: message);

  static Future<void> paymentError(double amount, double fee, bool payerCoversFee,
      PaymentType source,PaymentType recpientPaymentMethod, String message) async =>
      _paymentEvent("paymentError", amount, fee, payerCoversFee, source, recpientPaymentMethod,
          message: message);

  static Future<void> paymentSuccess({
    required double amount,
    required double fee,
    required bool payerCoversFee,
    required PaymentType source, 
    required PaymentType recpientPaymentMethod,
    required String transactionId,
    String? comment,
    required int durationMs,
  }) async {
    return _paymentEvent(
      "paymentSuccess",
      amount,
      fee,
      payerCoversFee,
      source,
      recpientPaymentMethod,
      message: comment,
      extraProps: {
        "transaction_id": transactionId,
        "duration_ms": durationMs, //How do i calculate duration here?
        "\$revenue": amount, //How do i calculate revenue here?
        "\$revenueType": "payment", //Do we need to get revenue type?
      },
    );
  }

  //TODO add when support is ready
  // static Future<void> supportOpened(String fromPage, String trigger) async =>
  //     _logEvent("supportOpened", eventProperties: {"from_page": fromPage, "trigger": trigger});

  // static Future<void> supportMessageSent(String category, bool resolved) async =>
  //     _logEvent("supportMessageSent", eventProperties: {"category": category, "resolved": resolved});


  static Future<void> walletTopUp(double amount, PaymentType method) async =>
      _logEvent("walletTopUp", eventProperties: {"amount": amount, "method": method});


  //TODO Decide do we need uiElementClicked or pageOpened is enough?
  static Future<void> uiElementClicked(String elementName, String page, String uiSource) async =>
      _logEvent("uiElementClicked", eventProperties: {
        "element_name": elementName,
        "page": page,
        "uiSource": uiSource
      });

  static final Map<String, int> _stepStartTimes = {};
  //TODO Consider it as part of payment flow or registration flow or adding recipient and rework accordingly
  static Future<void> stepStarted(String stepName, {String? context}) async {
    _stepStartTimes[stepName] = DateTime.now().millisecondsSinceEpoch;
    return _logEvent("stepStarted", eventProperties: {
      "step_name": stepName,
      if (context != null) "context": context,
    });
  }

  static Future<void> stepCompleted(String stepName, bool success) async {
    final now = DateTime.now().millisecondsSinceEpoch;
    final start = _stepStartTimes[stepName] ?? now;
    final duration = now - start;
    return _logEvent("stepCompleted", eventProperties: {
      "step_name": stepName,
      "duration_ms": duration,
      "success": success
    });
  }

  static Future<void> _logEvent(
    String eventType, {
    Map<String, dynamic>? eventProperties,
    Map<String, dynamic>? userProperties,
  }) async {
    final event = BaseEvent(
      eventType,
      eventProperties: eventProperties,
      userProperties: userProperties,
    );
    _amp().track(event);
    print(event.toString()); //TODO delete when everything is ready
  }
}