import { useEffect } from 'react';
import {
  HostComponent,
  NativeModules,
  Platform,
  UIManager,
  ViewProps,
  ViewStyle,
  findNodeHandle,
  NativeEventEmitter,
  DeviceEventEmitter,
  NativeSyntheticEvent,
  requireNativeComponent,
} from 'react-native';

const LINKING_ERROR =
  `The package 'react-native-tink-sdk' doesn't seem to be linked. Make sure: \n\n` +
  Platform.select({ ios: '- You have run pod install\n', default: '' }) +
  '- You rebuilt the app after installing the package\n';

const ReactNativeTink = NativeModules.ReactNativeTink
  ? NativeModules.ReactNativeTink
  : new Proxy(
      {},
      {
        get() {
          throw new Error(LINKING_ERROR);
        },
      }
    );

const tinkEventEmitter =
  Platform.OS === 'ios' ? new NativeEventEmitter(NativeModules.TinkEventEmitter) : DeviceEventEmitter;

/**
 * This is the method for initializing Tink Money manager SDK. Should be called only once
 * and is required only for Android.
 *
 * @param clientId - client ID retrieved from Tink Console.
 *
 */

export function initTink(clientId: string): Promise<any> {
  return ReactNativeTink.initTink(clientId);
}

/**
 * This is the params required for MoneyManagerFinanceOverview.
 *
 * @param style - define the width and length for the view. This will be taken effect in Andriod only.
 *                In iOS, the entire length and width will be taken.
 * @param clientId - client ID retrieved from Tink Console.
 * @param accessToken - access token generated with all the required scopes.
 *
 */
export type MoneyManagerFinanceOverviewProps = ViewProps & {
  style: ViewStyle;
  clientId: string;
  clientAccessToken: string;
  userAccessToken: string;
  userId: string;
  idHint: string;
  redirectUri: string;
  userPressedBack?: (event?: NativeSyntheticEvent<{}>) => void;
};

// Automatically resolves this to "MoneyManagerFinanceOverviewManager"
const MoneyManagerFinanceOverviewComponent: HostComponent<MoneyManagerFinanceOverviewProps> =
  requireNativeComponent('MoneyManagerFinanceOverview');

function _userPressedBack(props: MoneyManagerFinanceOverviewProps) {
  if (props.userPressedBack) {
    props.userPressedBack();
  }
}

// This is the view which contains the Money manager SDK screens.
export const MoneyManagerFinanceOverview = (props: MoneyManagerFinanceOverviewProps) => {
  const { style, clientId, userAccessToken, clientAccessToken, userId, idHint, redirectUri, userPressedBack } = props;

  let nativeComponentref: React.Component | null;

  const onCreate = () => {
    if (Platform.OS === 'android') {
      const androidViewId = findNodeHandle(nativeComponentref);

      UIManager.dispatchViewManagerCommand(
        androidViewId,
        // @ts-ignore
        UIManager.MoneyManagerFinanceOverview.Commands.create.toString(),
        [androidViewId]
      );
    }
  };

  function cleanListeners() {
    tinkEventEmitter.removeAllListeners('userPressedBack');
  }

  useEffect(() => {
    onCreate();
    cleanListeners();

    if (userPressedBack) {
      tinkEventEmitter.addListener('userPressedBack', () => _userPressedBack(props));
    }
  });

  return (
    <MoneyManagerFinanceOverviewComponent
      style={style}
      clientId={clientId}
      clientAccessToken={clientAccessToken}
      userAccessToken={userAccessToken}
      userId={userId}
      idHint={idHint}
      redirectUri={redirectUri}
      ref={nativeRef => (nativeComponentref = nativeRef)}
    />
  );
};

/**
 * This is the method for opening money manager view
 * and is required only for Android.
 *
 * @param clientId - client ID retrieved from Tink Console.
 * @param accessToken - access token generated with all the required scopes.
 *
 */

export function showMoneyManager(
  clientId: string,
  userAccessToken: string,
  appAccessToken: string,
  userId: string,
  idHint: string,
  actorClientId: string,
  scope: string,
  redirectUri: string
): Promise<any> {
  return ReactNativeTink.launchFinanceOverview(
    clientId,
    userAccessToken,
    appAccessToken,
    userId,
    idHint,
    actorClientId,
    scope,
    redirectUri
  );
}
