/* eslint-disable @typescript-eslint/no-explicit-any */

import EventAction from './EventAction';
import MapProvider from './MapProvider';
import { Provider, ProviderMethod, ProviderAttr, LoginStatus, EventSdk, ErrorHandler, LoggerHandler } from './types';

export default class SkipEventSdk implements EventSdk {
  private errorHandler?: ErrorHandler;

  private logger?: LoggerHandler;

  private map: MapProvider;

  private action: EventAction;

  constructor() {
    this.map = new MapProvider();
    this.action = new EventAction();
  }

  /**
   * @description Adds an error handler
   * @param {ErrorHandler} errorHandler
   */
  addErrorHandler(errorHandler: ErrorHandler): void {
    this.errorHandler = errorHandler;
  }

  /**
   * @description Adds an logger handler
   * @param {LoggerHandler} logger
   */
  addLogger(logger: LoggerHandler): void {
    this.logger = logger;
  }

  /**
   * @description Adds a new event provider
   * @param {Provider} provider - New provider
   * @returns {string} - Provider ID
   */
  addProvider(provider: Provider): string {
    return this.map.addProvider(provider);
  }

  /**
   * @description Removes a new event provider
   * @param {string} id - Provider ID
   * @memberof SkipEventSdk
   */
  deleteProvider(id: string): void {
    this.map.deleteProvider(id);
  }

  /**
   * @description Run the provider method
   * @private
   * @param {Function} action - Provider method
   * @param {*} payload - Provider method parameter
   * @param {string} providerName - Provider instance name
   */
  private execute(action: Function, payload: any, providerName: string): void {
    try {
      action(payload);
    } catch (err) {
      if (typeof this.errorHandler === 'function') {
        this.errorHandler(providerName, { name: action.name, stack: String(err), message: String(err) });
      }
    }
  }

  /**
   * @description Checks whether the provider has the method.
   * @private
   * @param {Provider} provider
   * @param {ProviderAttr} method
   * @returns {boolean}
   */
  private hasMethod(provider: Provider, method: ProviderAttr): boolean {
    return method in provider && typeof provider[method] === 'function';
  }

  /**
   * @description Scroll through the list of providers and perform their functions
   * @private
   * @param {ProviderAttr} keyFn - Provider method name
   * @param {*} payload - Provider method parameter
   * @param {Array<string>} [ids=[]] - Provider IDs
   */
  private runAll(keyFn: ProviderAttr, payload: any, ids: Array<string> = []): void {
    try {
      this.map.getProviders(ids).forEach((provider) => {
        if (this.hasMethod(provider, keyFn)) {
          const action = (provider[keyFn] as ProviderMethod).bind(provider);

          this.execute(action, payload, provider.constructor.name);

          if (typeof this.logger === 'function') {
            this.logger(provider.constructor.name, keyFn);
          }
        }
      });
    } catch (err) {
      if (typeof this.errorHandler === 'function') {
        this.errorHandler('Error before providers', { name: keyFn, stack: String(err), message: String(err) });
      }
    }
  }

  tryAppReviewed(payload: any, ids: Array<string>): void {
    this.runAll('appReviewed', payload, ids);
  }

  tryCharged(payload: any, ids: Array<string>): void {
    this.runAll('charged', payload, ids);
  }

  tryDeepLinkClicked(payload: any, ids: Array<string>): void {
    this.runAll('deepLinkClicked', payload, ids);
  }

  tryDeepLinkOpened(payload: any, ids: Array<string>): void {
    this.runAll('deepLinkOpened', payload, ids);
  }

  tryLogin(payload: LoginStatus, ids: Array<string>): void {
    this.runAll('login', payload, ids);
  }

  tryLogout(payload: any, ids: Array<string>): void {
    this.runAll('logout', payload, ids);
  }

  tryOnUserLogin(payload: any, ids: Array<string>): void {
    this.runAll('onUserLogin', payload, ids);
  }

  tryOnUserSelectReasons(payload: any, ids: Array<string>): void {
    this.runAll('onUserSelectReasons', payload, ids);
  }

  trySetUserLocation(payload: any, ids: Array<string>): void {
    this.runAll('setUserLocation', payload, ids);
  }

  tryUpdateFCMtoken(payload: any, ids: Array<string>): void {
    this.runAll('updateFCMtoken', payload, ids);
  }

  tryUserClicksSignUp(payload: any, ids: Array<string>): void {
    this.runAll('userClicksSignUp', payload, ids);
  }

  tryVisitsHomePage(payload: any, ids: Array<string>): void {
    this.runAll('visitsHomePage', payload, ids);
  }

  tryVisitsJoinPage(payload: any, ids: Array<string>): void {
    this.runAll('visitsJoinPage', payload, ids);
  }

  tryVisitsPremiumPage(payload: any, ids: Array<string>): void {
    this.runAll('visitsPremiumPage', payload, ids);
  }

  tryVisitsFreePage(payload: any, ids: Array<string>): void {
    this.runAll('visitsFreePage', payload, ids);
  }

  tryVisitsOnboarding(payload: any, ids: Array<string>): void {
    this.runAll('visitsOnboarding', payload, ids);
  }

  tryVisitsDashboard(payload: any, ids: Array<string>): void {
    this.runAll('visitsDashboard', payload, ids);
  }

  tryVisitsBusinessProfile(payload: any, ids: Array<string>): void {
    this.runAll('visitsBusinessProfile', payload, ids);
  }

  tryVisitsRemindersPage(payload: any, ids: Array<string>): void {
    this.runAll('visitsRemindersPage', payload, ids);
  }

  tryUserCompletesBusinessProfile(payload: any, ids: Array<string>): void {
    this.runAll('userCompletesBusinessProfile', payload, ids);
  }

  tryUserClickTodoItem(payload: any, ids: Array<string>): void {
    this.runAll('userClickTodoItem', payload, ids);
  }

  tryUserConfirmsSubscription(payload: any, ids: string[]): void {
    this.runAll('userConfirmsSubscription', payload, ids);
  }

  tryUserScheduledOnboardingCall(payload: any, ids: string[]): void {
    this.runAll('userScheduledOnboardingCall', payload, ids);
  }

  tryUserFeaturedBusinessOnSkip(payload: any, ids: string[]): void {
    this.runAll('userFeaturedBusinessOnSkip', payload, ids);
  }

  tryAccountCreated(payload: any, ids: string[]): void {
    this.runAll('accountCreated', payload, ids);
  }

  tryAccountCreatedError(payload: any, ids: string[]): void {
    this.runAll('accountCreatedError', payload, ids);
  }

  tryClickedAnnual(payload: any, ids: string[]): void {
    this.runAll('clickedAnnual', payload, ids);
  }

  tryClickedAutoSubCheckbox(payload: any, ids: string[]): void {
    this.runAll('clickedAutoSubCheckbox', payload, ids);
  }

  tryClickedCardNumberField(payload: any, ids: string[]): void {
    this.runAll('clickedCardNumberField', payload, ids);
  }

  tryClickedCheckAvailability(payload: any, ids: string[]): void {
    this.runAll('clickedCheckAvailability', payload, ids);
  }

  tryClickedConfirm(payload: any, ids: string[]): void {
    this.runAll('clickedConfirm', payload, ids);
  }

  tryClickedContinuetoDashboard(payload: any, ids: string[]): void {
    this.runAll('clickedContinuetoDashboard', payload, ids);
  }

  tryClickedDownloadApp(payload: any, ids: string[]): void {
    this.runAll('clickedDownloadApp', payload, ids);
  }

  tryClickedFunding(payload: any, ids: string[]): void {
    this.runAll('clickedFunding', payload, ids);
  }

  tryClickedLogin(payload: any, ids: string[]): void {
    this.runAll('clickedLogin', payload, ids);
  }

  tryClickedMonthly(payload: any, ids: string[]): void {
    this.runAll('clickedMonthly', payload, ids);
  }

  tryClickedPrivacyPolicy(payload: any, ids: string[]): void {
    this.runAll('clickedPrivacyPolicy', payload, ids);
  }

  tryClickedReferralEmailField(payload: any, ids: string[]): void {
    this.runAll('clickedReferralEmailField', payload, ids);
  }

  tryClickedReviewReadMore(payload: any, ids: string[]): void {
    this.runAll('clickedReviewReadMore', payload, ids);
  }

  tryClickedSaveNewPassword(payload: any, ids: string[]): void {
    this.runAll('clickedSaveNewPassword', payload, ids);
  }

  tryClickedSendInvites(payload: any, ids: string[]): void {
    this.runAll('clickedSendInvites', payload, ids);
  }

  tryClickedTermsandConditions(payload: any, ids: string[]): void {
    this.runAll('clickedTermsandConditions', payload, ids);
  }

  tryPaymentVerifiedError(payload: any, ids: string[]): void {
    this.runAll('paymentVerifiedError', payload, ids);
  }

  tryPaymentVerifiedSuccess(payload: any, ids: string[]): void {
    this.runAll('paymentVerifiedSuccess', payload, ids);
  }

  trySaveNewPasswordError(payload: any, ids: string[]): void {
    this.runAll('saveNewPasswordError', payload, ids);
  }

  tryViewedCalendlyCalendar(payload: any, ids: string[]): void {
    this.runAll('viewedCalendlyCalendar', payload, ids);
  }

  tryViewedNewPasswordPage(payload: any, ids: string[]): void {
    this.runAll('viewedNewPasswordPage', payload, ids);
  }

  tryViewedPaymentInfo(payload: any, ids: string[]): void {
    this.runAll('viewedPaymentInfo', payload, ids);
  }

  tryViewedPlusPage(payload: any, ids: string[]): void {
    this.runAll('viewedPlusPage', payload, ids);
  }

  tryViewedPremiumConciergePage(payload: any, ids: string[]): void {
    this.runAll('viewedPremiumConciergePage', payload, ids);
  }

  tryViewedPlatinumConciergePage(payload: any, ids: string[]): void {
    this.runAll('viewedPlatinumConciergePage', payload, ids);
  }

  // plop

  tryAddedLoanApplicationTracking(payload: any, ids: string[]): void {
    this.runAll('addedLoanApplicationTracking', payload, ids);
  }

  tryClickedServiceFlow(payload: any, ids: string[]): void {
    this.runAll('clickedServiceFlow', payload, ids);
  }

  tryUpgradedFromAccountDetails(payload: any, ids: string[]): void {
    this.runAll('upgradedFromAccountDetails', payload, ids);
  }

  tryUpgradedFromLatestFundingOpportunity(payload: any, ids: string[]): void {
    this.runAll('upgradedFromLatestFundingOpportunity', payload, ids);
  }

  tryAddedFundingGoal(payload: any, ids: string[]): void {
    this.runAll('addedFundingGoal', payload, ids);
  }

  tryClickOnBlog(payload: any, ids: string[]): void {
    this.runAll('clickOnBlog', payload, ids);
  }

  tryNotInterestedInFundingOpportunity(payload: any, ids: string[]): void {
    this.runAll('notInterestedInFundingOpportunity', payload, ids);
  }

  trySharedReferralLink(payload: any, ids: string[]): void {
    this.runAll('sharedReferralLink', payload, ids);
  }

  tryExitedAddBusinessModal(payload: any, ids: string[]): void {
    this.runAll('exitedAddBusinessModal', payload, ids);
  }

  tryAddedBusiness(payload: any, ids: string[]): void {
    this.runAll('addedBusiness', payload, ids);
  }

  tryInvitesAFriend(payload: any, ids: string[]): void {
    this.runAll('invitesAFriend', payload, ids);
  }
}
