import { BigNumber } from 'ethers';
import { omit } from 'lodash';
import { SignatureLike } from '@ethersproject/bytes';
import { verifyMessage, verifyTypedData } from 'ethers/lib/utils';
import { v4 as uuidv4 } from 'uuid';
import {
  Transaction,
  TransactionInstruction,
  VersionedTransaction,
} from '@solana/web3.js';
import {
  getAppInfo,
  initRequestToken,
  logout,
  optAutoApproveState,
} from './api';
import { IDomain, ITypes, IMessage } from './defination';
import {
  bufferToTransaction,
  closeModal,
  DEVICE_TYPE,
  getUserAgent,
  initModal,
  showModal,
} from './utils';
import SDKStorage from './store';

const clearLoopObserver = (
  clientWindow: Window | null,
  handleMessage: (e: any) => void,
) => {
  const interval = setInterval(function () {
    if (!clientWindow || clientWindow.closed) {
      clearInterval(interval);
      window.removeEventListener('message', handleMessage);
    }
  }, 500);
  return interval;
};

const checkWindowOpenStatus = (
  clientWindow: Window | null,
  reject: (reason?: any) => void,
  msg: any = 'The pop-up cannot be ejected',
) => {
  const id = setTimeout(() => {
    clearTimeout(id);
    if (!clientWindow) {
      reject(msg);
    }
  }, 2000);
};

const envPromiseCheckWrapper = <T>(
  callback: (
    res: (value: any | PromiseLike<any>) => void,
    rej: (reason?: any) => void,
  ) => any,
  clientWindow: Window | null,
  msg?: any,
): Promise<T> => {
  return new Promise((resolve, reject) => {
    checkWindowOpenStatus(clientWindow, reject, msg);
    callback(resolve, reject);
  });
};

interface FSLLoginOptions {
  responseType?: string;

  appKey: string;

  redirectUri?: string;

  scope?: string;

  state?: string;

  usePopup?: boolean;

  useModal?: boolean;

  isApp?: boolean;

  domain?: string;

  uid?: number;
}

class FSLAuthorization {
  responseType?: string;
  appKey: string;
  redirectUri?: string;
  scope?: string;
  state?: string;
  usePopup?: boolean;
  useModal?: boolean;
  domain: string = 'https://id.fsl.com';
  isApp?: boolean;
  inWhiteList: boolean;
  requestToken?: string;
  sdkStorage?: SDKStorage;
  uid?: number;
  handling: boolean;
  windowFeatures = `left=${window.screen.width / 2 - 200},top=${
    window.screen.height / 2 - 500
  },width=500,height=800,popup=1`;
  private constructor(opt: FSLLoginOptions) {
    const {
      responseType,
      appKey,
      redirectUri,
      scope,
      state,
      useModal,
      usePopup,
      domain,
      isApp,
      uid,
    } = opt;
    this.appKey = appKey;
    this.responseType = responseType;
    this.redirectUri = redirectUri;
    this.scope = scope;
    this.usePopup = usePopup;
    this.useModal = useModal;
    this.state = state;
    this.isApp = isApp;
    this.inWhiteList = false;
    this.uid = uid;
    this.handling = false;
    if (domain) this.domain = domain;
    window.origin = this.domain;
    if (this.uid) {
      this.sdkStorage = new SDKStorage(this.uid + '');
      const token = this.sdkStorage.getItem('token') as string;
      if (token) initRequestToken(token);
    }
  }

  static async init(opt: FSLLoginOptions) {
    const auth = new FSLAuthorization(opt);
    try {
      if (opt.useModal) {
        const { state } = (await getAppInfo(opt.appKey)) as any;
        if (state & 1) {
          auth.inWhiteList = true;
          initModal(opt.domain);
        }
      }
    } catch (err: any) {
      console.log(err.msg || err.message);
    }
    return auth;
  }

  async getApproveDDL() {
    return optAutoApproveState(this.appKey);
  }

  async openAutoApprove() {
    return optAutoApproveState(this.appKey, 1);
  }

  async closeAutoApprove() {
    return optAutoApproveState(this.appKey, -1);
  }

  async signIn(args?: { withState: boolean }) {
    const callUrl = new URL(`${this.domain}/login/fslUsers`);
    const commonArgs: Record<string, string | undefined> = {
      response_type: this.responseType,
      appkey: this.appKey,
      scope: this.scope,
      state: this.state,
      is_app: this.isApp ? '1' : undefined,
      withState: args?.withState ? '1' : undefined,
    };
    for (let key in commonArgs) {
      if (commonArgs[key]) {
        callUrl.searchParams.append(key, commonArgs[key]!);
      }
    }
    if (this.inWhiteList && this.useModal) {
      callUrl.searchParams.append('use_modal', '1');
      getUserAgent() !== DEVICE_TYPE.PC &&
        callUrl.searchParams.append('isMobile', '1');
      showModal(callUrl.toString());
      return new Promise((resolve) => {
        window.handleMessage = (e: any) => {
          if (e.data.type === 'fsl_auth') {
            resolve(omit(e.data.data, 'requestToken', 'id'));
            this.uid = +e.data.data.id;
            this.sdkStorage = new SDKStorage(e.data.data.id + '');
            this.sdkStorage.setItem('token', e.data.data.requestToken);
            e.data.data.requestToken &&
              initRequestToken(e.data.data.requestToken);
            window.removeEventListener('message', window.handleMessage!);
            closeModal();
            window.handleMessage = null;
          }
        };
        window.addEventListener('message', window.handleMessage, false);
      });
    }

    if (!this.usePopup) {
      callUrl.searchParams.append('redirect_uri', this.redirectUri!);
      location.href = callUrl.toString();
      return Promise.resolve(null);
    } else {
      callUrl.searchParams.append('use_popup', '1');
      if (this.isApp) {
        callUrl.searchParams.append('redirect_uri', this.redirectUri!);
      }
      const clientWindow = window.open(
        callUrl.toString(),
        this.isApp ? '_blank' : `signWindow`,
        this.windowFeatures,
      );
      if (this.isApp) {
        return Promise.resolve(null);
      }
      return envPromiseCheckWrapper((resolve) => {
        const handleMessage = (e: any) => {
          if (e.data.type === 'fsl_auth') {
            resolve(e.data.data);
            window.removeEventListener('message', handleMessage);
          }
        };
        window.addEventListener('message', handleMessage, false);
        clearLoopObserver(clientWindow, handleMessage);
      }, clientWindow);
    }
  }

  async signOut() {
    this.sdkStorage?.removeItem('token');
    return logout();
  }

  async signInV2() {
    return this.signIn({ withState: true });
  }

  async checkAndAutoHandle<T>(
    uid: number | undefined,
    callUrl: URL,
    params: Record<string, any>,
    format?: (data: any) => T,
  ): Promise<T | any> {
    if (this.handling) {
      return Promise.reject({
        message:
          'There is currently one transaction that has not been processed',
      });
    }
    this.handling = true;
    let time = 0;
    let childFrame: HTMLIFrameElement;
    if (
      uid &&
      (!this.sdkStorage || +(this.sdkStorage.getItem('id') as string) !== uid)
    ) {
      this.sdkStorage = new SDKStorage(uid + '');
      const token = this.sdkStorage.getItem('token') as string;
      if (token) initRequestToken(token);
    }
    try {
      time = (await this.getApproveDDL()) as unknown as number;
    } catch (err) {
      this.handling = false;
      return err;
    }
    let token = undefined;
    const terminalType = getUserAgent();
    if (terminalType === DEVICE_TYPE.IOS) {
      token = this.sdkStorage!.getItem('token') as string;
    }
    if (time) {
      const url = new URL(`${this.domain}/authorization/silent`);
      url.search = callUrl.search;
      token && url.searchParams.append('token', token);
      childFrame = showModal(url.toString(), true);
    } else {
      terminalType !== DEVICE_TYPE.PC &&
        callUrl.searchParams.append('isMobile', '1');
      token && callUrl.searchParams.append('token', token);
      childFrame = showModal(callUrl.toString());
    }
    return new Promise((resolve, reject) => {
      window.handleMessage = (e: any) => {
        if (e.data.type === 'fsl_auth') {
          if (typeof e.data.data === 'string') {
            if (e.data.data === 'done') {
              childFrame &&
                childFrame.contentWindow?.postMessage(
                  {
                    type: 'fsl_params',
                    data: JSON.stringify(params),
                  },
                  this.domain,
                );
              return;
            } else {
              resolve(e.data.data);
            }
          } else if (
            typeof e.data.data === 'object' &&
            ('msg' in e.data.data || 'message' in e.data.data)
          ) {
            reject(e.data.data);
          } else {
            const data = format ? format(e.data.data) : e.data.data;
            resolve(data);
          }
          window.removeEventListener('message', window.handleMessage!);
          closeModal();
          window.handleMessage = null;
          this.handling = false;
        }
      };
      window.addEventListener('message', window.handleMessage, false);
    });
  }

  static evmVerifyMessage(msg: string, signature: SignatureLike) {
    return verifyMessage(msg, signature);
  }

  static evmVerifyTypedData(
    domain: IDomain,
    types: ITypes,
    message: IMessage,
    signature: SignatureLike,
  ) {
    return verifyTypedData(domain, types, message, signature);
  }

  async callEvmSign(args: {
    msg: any;
    rpc?: string;
    chainId: number;
    chain?: string;
    domain?: string;
    uid?: number;
    signDigest?: boolean;
  }) {
    const { msg, chainId, chain, rpc, signDigest, uid = this.uid } = args;
    const callUrl = new URL(`${args.domain || this.domain}/authorization/sign`);
    let type: string;
    switch (true) {
      case msg instanceof Uint8Array:
        type = 'unit8Array';
        break;
      case msg instanceof Uint16Array:
        type = 'unit16Array';
        break;
      case msg instanceof Uint32Array:
        type = 'unit32Array';
        break;
      default:
        type = '';
    }

    const uuid = uuidv4();

    callUrl.searchParams.append(
      'arguments',
      JSON.stringify({
        id: uuid,
        appKey: this.appKey,
        chainId,
        chain,
      }),
    );

    if (uid) {
      callUrl.searchParams.append('uid', uid + '');
    }
    if (this.useModal && this.inWhiteList) {
      return this.checkAndAutoHandle(uid, callUrl, {
        id: uuid,
        msg,
        type,
        rpc,
        signDigest: signDigest ? 1 : undefined,
        name: 'callEvmSign',
      });
    }
    const url = callUrl.toString();

    const clientWindow = window.open(url, `evmSignWindow`, this.windowFeatures);
    return envPromiseCheckWrapper((resolve, reject) => {
      const handleMessage = (e: any) => {
        if (e.data.type === 'fsl_auth') {
          if (typeof e.data.data === 'string') {
            if (e.data.data === 'done') {
              clientWindow &&
                clientWindow.postMessage(
                  {
                    type: 'fsl_params',
                    data: JSON.stringify({
                      id: uuid,
                      msg,
                      type,
                      rpc,
                      signDigest: signDigest ? 1 : undefined,
                    }),
                  },
                  '*',
                );
              return;
            } else {
              resolve(e.data.data);
            }
          } else {
            reject(e.data.data);
          }
          window.removeEventListener('message', handleMessage);
        }
      };
      window.addEventListener('message', handleMessage, false);
      clearLoopObserver(clientWindow, handleMessage);
    }, clientWindow);
  }

  async callEvmSignDigest(args: {
    msg: any;
    rpc?: string;
    chainId: number;
    chain?: string;
    domain?: string;
    uid?: number;
  }) {
    return this.callEvmSign({ ...args, signDigest: true });
  }

  async signTypedData(args: {
    domain: IDomain;
    types: ITypes;
    message: IMessage;
    chainId: number;
    mockDomain?: string;
    chain?: string;
    uid?: number;
  }) {
    const {
      domain,
      types,
      message,
      mockDomain,
      chain,
      chainId,
      uid = this.uid,
    } = args;
    const uuid = uuidv4();

    const callUrl = new URL(
      `${mockDomain || this.domain}/authorization/sign-v4`,
    );

    callUrl.searchParams.append(
      'arguments',
      JSON.stringify({
        id: uuid,
        appKey: this.appKey,
      }),
    );

    if (uid) {
      callUrl.searchParams.append('uid', uid + '');
    }

    if (this.useModal && this.inWhiteList) {
      return this.checkAndAutoHandle(uid, callUrl, {
        message,
        chain,
        chainId,
        types,
        domain,
        id: uuid,
        name: 'signTypedData',
      });
    }
    const url = callUrl.toString();

    const clientWindow = window.open(
      url,
      `typedSignWindow`,
      this.windowFeatures,
    );
    return envPromiseCheckWrapper((resolve, reject) => {
      const handleMessage = (e: any) => {
        if (e.data.type === 'fsl_auth') {
          if (typeof e.data.data === 'string') {
            if (e.data.data === 'done') {
              clientWindow &&
                clientWindow.postMessage(
                  {
                    type: 'fsl_params',
                    data: JSON.stringify({
                      message,
                      chain,
                      chainId,
                      types,
                      domain,
                      id: uuid,
                    }),
                  },
                  '*',
                );
            } else {
              resolve(e.data.data);
              window.removeEventListener('message', handleMessage);
            }
          } else {
            reject(e.data.data);
            window.removeEventListener('message', handleMessage);
          }
        }
      };
      window.addEventListener('message', handleMessage, false);
      clearLoopObserver(clientWindow, handleMessage);
    }, clientWindow);
  }

  async callEvmContractByCallData(args: {
    contractAddress: string;
    callData: string;
    chainId: number;
    gasLimit: string;
    value?: string;
    chain?: string;
    rpc?: string;
    domain?: string;
    nonce?: number;
    onlySign?: boolean;
    maxPriorityFeePerGasValue?: BigNumber;
    maxFeePerGasValue?: BigNumber;
    uid?: number;
    confirmed?: boolean;
  }) {
    const uuid = uuidv4();
    const {
      contractAddress,
      callData,
      chainId,
      gasLimit,
      value,
      chain,
      rpc,
      domain,
      nonce,
      onlySign,
      maxPriorityFeePerGasValue,
      maxFeePerGasValue,
      uid = this.uid,
      confirmed = false,
    } = args;

    const callUrl = new URL(`${domain || this.domain}/authorization/call-data`);

    callUrl.searchParams.append(
      'arguments',
      JSON.stringify({
        id: uuid,
        appKey: this.appKey,
        chainId,
        chain,
        onlySign: onlySign ? 'onlySign' : undefined,
      }),
    );

    if (uid) {
      callUrl.searchParams.append('uid', uid + '');
    }

    if (this.useModal && this.inWhiteList) {
      return this.checkAndAutoHandle(uid, callUrl, {
        contractAddress,
        callData,
        gasLimit,
        value,
        rpc,
        chainId,
        chain,
        nonce,
        onlySign: onlySign ? 'onlySign' : undefined,
        maxFeePerGasValue,
        maxPriorityFeePerGasValue,
        id: uuid,
        confirmed,
        name: 'callEvmContractByCallData',
      });
    }
    const url = callUrl.toString();
    const clientWindow = window.open(
      url,
      `callDataWindow`,
      this.windowFeatures,
    );
    return envPromiseCheckWrapper((resolve, reject) => {
      const handleMessage = (e: any) => {
        if (e.data.type === 'fsl_auth') {
          if (typeof e.data.data === 'string') {
            if (e.data.data === 'done') {
              clientWindow &&
                clientWindow.postMessage(
                  {
                    type: 'fsl_params',
                    data: JSON.stringify({
                      contractAddress,
                      callData,
                      chainId,
                      gasLimit,
                      value,
                      chain,
                      rpc,
                      nonce,
                      maxFeePerGasValue,
                      maxPriorityFeePerGasValue,
                      id: uuid,
                      confirmed,
                    }),
                  },
                  '*',
                );
            } else {
              resolve(e.data.data);
              window.removeEventListener('message', handleMessage);
            }
          } else if (
            typeof e.data.data === 'object' &&
            'transactionHash' in e.data.data
          ) {
            resolve(e.data.data);
            window.removeEventListener('message', handleMessage);
          } else {
            reject(e.data.data);
            window.removeEventListener('message', handleMessage);
          }
        }
      };
      window.addEventListener('message', handleMessage, false);
      clearLoopObserver(clientWindow, handleMessage);
    }, clientWindow);
  }

  async signCallDataTransaction(args: {
    contractAddress: string;
    callData: string;
    chainId: number;
    gasLimit: string;
    value?: string;
    chain?: string;
    rpc?: string;
    domain?: string;
    nonce?: number;
    maxPriorityFeePerGasValue?: BigNumber;
    maxFeePerGasValue?: BigNumber;
    uid?: number;
  }) {
    return this.callEvmContractByCallData({ ...args, onlySign: true });
  }

  async signSolMessage(args: { msg: string; domain?: string; uid?: number }) {
    const { msg, domain, uid = this.uid } = args;
    const uuid = uuidv4();
    const callUrl = new URL(`${domain || this.domain}/authorization/sol-sign`);
    callUrl.searchParams.append(
      'arguments',
      JSON.stringify({
        id: uuid,
        appKey: this.appKey,
      }),
    );

    if (uid) {
      callUrl.searchParams.append('uid', uid + '');
    }

    if (this.useModal && this.inWhiteList) {
      return this.checkAndAutoHandle(uid, callUrl, {
        msg,
        id: uuid,
        name: 'signSolMessage',
      });
    }

    const url = callUrl.toString();
    const clientWindow = window.open(
      url,
      `signSolMsgWindow`,
      this.windowFeatures,
    );

    return envPromiseCheckWrapper((resolve, reject) => {
      const handleMessage = (e: any) => {
        if (e.data.type === 'fsl_auth') {
          if (typeof e.data.data === 'string') {
            if (e.data.data === 'done') {
              clientWindow &&
                clientWindow.postMessage(
                  {
                    type: 'fsl_params',
                    data: JSON.stringify({
                      msg,
                      id: uuid,
                    }),
                  },
                  '*',
                );
            }
          } else if (
            e.data.data &&
            typeof e.data.data === 'object' &&
            'length' in e.data.data
          ) {
            resolve(e.data.data);
          } else {
            reject(e.data.data);
          }
          window.removeEventListener('message', handleMessage);
        }
      };
      window.addEventListener('message', handleMessage, false);
      clearLoopObserver(clientWindow, handleMessage);
    }, clientWindow);
  }

  async callSolInstructions(args: {
    instructions: TransactionInstruction[];
    rpc?: string;
    unitLimit?: number;
    unitPrice?: number;
    domain?: string;
    onlySign?: boolean;
    uid?: number;
  }) {
    const {
      domain,
      instructions,
      rpc,
      unitPrice,
      unitLimit,
      onlySign,
      uid = this.uid,
    } = args;
    const uuid = uuidv4();

    const callUrl = new URL(`${domain || this.domain}/authorization/sol-trade`);
    callUrl.searchParams.append(
      'arguments',
      JSON.stringify({
        appKey: this.appKey,
        onlySign: onlySign ? 'onlySign' : void 0,
        id: uuid,
      }),
    );

    if (uid) {
      callUrl.searchParams.append('uid', uid + '');
    }

    if (this.useModal && this.inWhiteList) {
      return this.checkAndAutoHandle(uid, callUrl, {
        instructions,
        unitLimit,
        unitPrice,
        id: uuid,
        rpc,
        onlySign: onlySign ? 'onlySign' : void 0,
        name: 'callSolInstructions',
      });
    }

    const url = callUrl.toString();
    const clientWindow = window.open(
      url,
      `signSolCallWindow`,
      this.windowFeatures,
    );

    return envPromiseCheckWrapper((resolve, reject) => {
      const handleMessage = async (e: any) => {
        if (e.data.type === 'fsl_auth') {
          if (typeof e.data.data === 'string') {
            if (e.data.data === 'done') {
              clientWindow &&
                clientWindow.postMessage(
                  {
                    type: 'fsl_params',
                    data: JSON.stringify({
                      instructions,
                      unitLimit,
                      unitPrice,
                      rpc,
                      id: uuid,
                    }),
                  },
                  '*',
                );
            } else {
              resolve(e.data.data);
              window.removeEventListener('message', handleMessage);
            }
          } else {
            reject(e.data.data);
            window.removeEventListener('message', handleMessage);
          }
        }
      };
      window.addEventListener('message', handleMessage, false);
      clearLoopObserver(clientWindow, handleMessage);
    }, clientWindow);
  }

  async signSolInstructions(args: {
    instructions: any[];
    rpc?: string;
    unitLimit?: number;
    unitPrice?: number;
    domain?: string;
    uid?: number;
  }) {
    return this.callSolInstructions({ ...args, onlySign: true });
  }

  async signSolTransaction(args: {
    transactions: Array<Transaction> | Array<VersionedTransaction>;
    uid?: number;
  }): Promise<Array<Transaction> | Array<VersionedTransaction>> {
    const { transactions, uid = this.uid } = args;
    let bufferStrs: string[] = [];
    const versions: Array<'legacy' | 0> = [];

    try {
      bufferStrs = transactions.map((item: any) => {
        if (item.version === 0) {
          versions.push(0);
          return Buffer.from(
            item.serialize({ verifySignatures: false }),
          ).toString('base64');
        } else {
          versions.push('legacy');
          return item.serialize({ verifySignatures: false }).toString('base64');
        }
      });
    } catch (err: any) {
      return Promise.reject(err.message);
    }

    const uuid = uuidv4();

    const callUrl = new URL(`${this.domain}/authorization/sol-transaction`);
    callUrl.searchParams.append(
      'arguments',
      JSON.stringify({
        id: uuid,
        appKey: this.appKey,
      }),
    );

    if (uid) {
      callUrl.searchParams.append('uid', uid + '');
    }

    if (this.useModal && this.inWhiteList) {
      return this.checkAndAutoHandle<
        Array<Transaction> | Array<VersionedTransaction>
      >(
        uid,
        callUrl,
        {
          transactions: bufferStrs,
          versions,
          id: uuid,
          name: 'signSolTransaction',
        },
        (data: any) => {
          let transactions = data;
          if (Array.isArray(data)) {
            transactions = bufferToTransaction(data, versions);
          }
          return transactions;
        },
      );
    }

    const url = callUrl.toString();
    const clientWindow = window.open(
      url,
      `signSolTrsWindow`,
      this.windowFeatures,
    );

    return envPromiseCheckWrapper((resolve, reject) => {
      const handleMessage = async (e: any) => {
        if (e.data.type === 'fsl_auth') {
          if (typeof e.data.data === 'string') {
            if (e.data.data === 'done') {
              clientWindow &&
                clientWindow.postMessage(
                  {
                    type: 'fsl_params',
                    data: JSON.stringify({
                      transactions: bufferStrs,
                      versions,
                      id: uuid,
                    }),
                  },
                  '*',
                );
            }
            return;
          } else if (Array.isArray(e.data.data)) {
            const transactions = bufferToTransaction(e.data.data, versions);
            resolve(transactions);
          } else {
            reject(e.data.data);
          }
          window.removeEventListener('message', handleMessage);
        }
      };
      window.addEventListener('message', handleMessage, false);
      clearLoopObserver(clientWindow, handleMessage);
    }, clientWindow);
  }

  async callEvmContract(args: {
    contractAddress: string;
    methodName: string;
    abi?: any;
    chainId: number;
    chain?: string;
    value?: string;
    gasLimit: string;
    params?: any[];
    to?: string;
    rpc?: string;
    domain?: string;
    nonce?: number;
    maxPriorityFeePerGasValue?: BigNumber;
    maxFeePerGasValue?: BigNumber;
    onlySign?: boolean;
    uid?: number;
  }) {
    const {
      contractAddress,
      methodName,
      abi,
      chainId,
      chain,
      value,
      gasLimit,
      params,
      to,
      rpc,
      domain,
      nonce,
      maxPriorityFeePerGasValue,
      maxFeePerGasValue,
      onlySign,
      uid = this.uid,
    } = args;
    const id = uuidv4();

    const callUrl = new URL(`${domain || this.domain}/authorization/trade-v2`);
    callUrl.searchParams.append(
      'arguments',
      JSON.stringify({
        appKey: this.appKey,
        onlySign: onlySign ? 'onlySign' : undefined,
        chainId,
        chain,
        id,
      }),
    );

    if (uid) {
      callUrl.searchParams.append('uid', uid + '');
    }

    const url = callUrl.toString();

    if (this.useModal && this.inWhiteList) {
      return this.checkAndAutoHandle(uid, callUrl, {
        contractAddress,
        methodName,
        abi,
        value,
        gasLimit,
        params,
        to,
        nonce,
        maxPriorityFeePerGasValue,
        maxFeePerGasValue,
        id,
        rpc,
        onlySign: onlySign ? 'onlySign' : undefined,
        name: 'callEvmContract',
      });
    }

    const clientWindow = window.open(
      url,
      `evmContractWindow`,
      this.windowFeatures,
    );
    return envPromiseCheckWrapper((resolve, reject) => {
      const handleMessage = (e: any) => {
        if (e.data.type === 'fsl_auth') {
          if (typeof e.data.data === 'string') {
            if (e.data.data === 'done') {
              clientWindow &&
                clientWindow.postMessage(
                  {
                    type: 'fsl_params',
                    data: JSON.stringify({
                      contractAddress,
                      methodName,
                      abi,
                      value,
                      gasLimit,
                      params,
                      to,
                      nonce,
                      maxPriorityFeePerGasValue,
                      maxFeePerGasValue,
                      id,
                      rpc,
                    }),
                  },
                  '*',
                );
            } else {
              resolve(e.data.data);
              window.removeEventListener('message', handleMessage);
            }
          } else if (
            e.data.data &&
            typeof e.data.data === 'object' &&
            'transactionHash' in e.data.data
          ) {
            resolve(e.data.data);
            window.removeEventListener('message', handleMessage);
          } else {
            reject(e.data.data);
            window.removeEventListener('message', handleMessage);
          }
        }
      };
      window.addEventListener('message', handleMessage, false);
      clearLoopObserver(clientWindow, handleMessage);
    }, clientWindow);
  }
  async signEvmContract(args: {
    contractAddress: string;
    methodName: string;
    abi?: any;
    chainId: number;
    chain?: string;
    value?: string;
    gasLimit: string;
    params?: any[];
    to?: string;
    rpc?: string;
    domain?: string;
    nonce?: number;
    maxPriorityFeePerGasValue?: BigNumber;
    maxFeePerGasValue?: BigNumber;
    uid?: number;
  }) {
    return this.callEvmContract({ ...args, onlySign: true });
  }
}

export default FSLAuthorization;
