// import { get } from "@toruslabs/http-helpers";
import { JRPCMiddleware, PendingJRPCResponse, SafeEventEmitter } from "@toruslabs/openlogin-jrpc";
import { ethErrors } from "eth-rpc-errors";
import { LogLevelDesc } from "loglevel";

import config from "./config";
import {
  IntegrityParams,
  LoginConfig,
  LoginConfigItem,
  PAYMENT_PROVIDER,
  PAYMENT_PROVIDER_TYPE,
  PaymentParams,
  UPBOND_BUILD_ENV_TYPE,
} from "./interfaces";
import log from "./loglevel";

const { paymentProviders } = config;

type PaymentErrorParams = {
  fiatValue?: string;
  selectedCurrency?: string;
  selectedCryptoCurrency?: string;
};

type PaymentErrors = { provider?: string } & PaymentErrorParams;

export const defaultLoginParam = {
  "upbond-line": {
    name: "LINE",
    description: "LINE",
    typeOfLogin: "line",
    loginProvider: "upbond-line",
    jwtParameters: {
      domain: "https://lzg2dndj.auth.dev.upbond.io",
      connection: "line",
      clientId: "FoQ_Ri8rKSXkHf82GRzZK",
      scope: "openid email profile offline_access",
    },
    clientId: "BGbtA2oA0SYvm1fipIPaSgSTPfGJG8Q6Ep_XHuZY9qQVW5jUXTMd0l8xVtXPx91aCmFfuVqTZt9CK79BgHTNanU",
    showOnModal: true,
    showOnDesktop: true,
    showOnMobile: true,
    mainOption: true,
    priority: 1,
    customLogo: "line",
    logo: "https://elvira.co.th/wp-content/uploads/2016/02/line-icon.png",
    buttonBgColor: "#289B2A",
    buttonTextColor: "#f3f3f3",
  } as LoginConfigItem,
  "upbond-google": {
    name: "Google",
    description: "Google",
    typeOfLogin: "jwt",
    loginProvider: "upbond-google",
    jwtParameters: {
      domain: "https://lzg2dndj.auth.dev.upbond.io",
      connection: "line",
      clientId: "hxFv4SaQVXv3tE_rhe5u9",
      scope: "openid email profile offline_access",
    },
    clientId: "BGbtA2oA0SYvm1fipIPaSgSTPfGJG8Q6Ep_XHuZY9qQVW5jUXTMd0l8xVtXPx91aCmFfuVqTZt9CK79BgHTNanU",
    showOnModal: true,
    showOnDesktop: true,
    showOnMobile: true,
    mainOption: true,
    priority: 2,
    customLogo: "google",
    logo: "https://www.seekpng.com/png/full/788-7887426_google-g-png-google-logo-white-png.png",
    buttonBgColor: "#4B68AE",
    buttonTextColor: "#FFF",
  } as LoginConfigItem,
} as LoginConfig;

export const defaultLoginParamStg = {
  "upbond-line": {
    name: "LINE",
    description: "LINE",
    typeOfLogin: "line",
    loginProvider: "upbond-line",
    jwtParameters: {
      domain: "https://6a8e4595.auth.stg.upbond.io",
      connection: "line",
      clientId: "YQvxSsSNOIFgoEwZoiPdm",
      scope: "openid email profile offline_access",
    },
    clientId: "BGbtA2oA0SYvm1fipIPaSgSTPfGJG8Q6Ep_XHuZY9qQVW5jUXTMd0l8xVtXPx91aCmFfuVqTZt9CK79BgHTNanU",
    showOnModal: true,
    showOnDesktop: true,
    showOnMobile: true,
    mainOption: true,
    priority: 1,
    customLogo: "line",
    logo: "https://elvira.co.th/wp-content/uploads/2016/02/line-icon.png",
    buttonBgColor: "#289B2A",
    buttonTextColor: "#f3f3f3",
  } as LoginConfigItem,
  "upbond-google": {
    name: "Google",
    description: "Google",
    typeOfLogin: "jwt",
    loginProvider: "upbond-google",
    jwtParameters: {
      domain: "https://6a8e4595.auth.stg.upbond.io",
      connection: "line",
      clientId: "zYvDxb22eVYLqDMAp_ql9",
      scope: "openid email profile offline_access",
    },
    clientId: "BGbtA2oA0SYvm1fipIPaSgSTPfGJG8Q6Ep_XHuZY9qQVW5jUXTMd0l8xVtXPx91aCmFfuVqTZt9CK79BgHTNanU",
    showOnModal: true,
    showOnDesktop: true,
    showOnMobile: true,
    mainOption: true,
    priority: 2,
    customLogo: "google",
    logo: "https://www.seekpng.com/png/full/788-7887426_google-g-png-google-logo-white-png.png",
    buttonBgColor: "#4B68AE",
    buttonTextColor: "#FFF",
  } as LoginConfigItem,
} as LoginConfig;

export const defaultLoginParamProd = {
  "upbond-line": {
    name: "LINE",
    description: "LINE",
    typeOfLogin: "line",
    loginProvider: "upbond-line",
    jwtParameters: {
      domain: "https://auth.upbond.io",
      connection: "line",
      clientId: "wa3wjaB0dx0RO9AgzngM-",
      scope: "openid email profile offline_access",
    },
    clientId: "BKmNTSQ7y8yWyhNT_W5BobaAu7Re-zLW6fzK0bzdvjP9a-G4OP8ajriQJHFOH3ypvRIJeEp_O40aag-7iNTyp-s",
    showOnModal: true,
    showOnDesktop: true,
    showOnMobile: true,
    mainOption: true,
    priority: 1,
    customLogo: "line",
    logo: "https://elvira.co.th/wp-content/uploads/2016/02/line-icon.png",
    buttonBgColor: "#289B2A",
    buttonTextColor: "#f3f3f3",
  } as LoginConfigItem,
  "upbond-google": {
    name: "Google",
    description: "Google",
    typeOfLogin: "jwt",
    loginProvider: "upbond-google",
    jwtParameters: {
      domain: "https://auth.upbond.io",
      connection: "line",
      clientId: "hxFv4SaQVXv3tE_rhe5u9",
      scope: "openid email profile offline_access",
    },
    clientId: "BKmNTSQ7y8yWyhNT_W5BobaAu7Re-zLW6fzK0bzdvjP9a-G4OP8ajriQJHFOH3ypvRIJeEp_O40aag-7iNTyp-s",
    showOnModal: true,
    showOnDesktop: true,
    showOnMobile: true,
    mainOption: true,
    priority: 2,
    customLogo: "google",
    logo: "https://www.seekpng.com/png/full/788-7887426_google-g-png-google-logo-white-png.png",
    buttonBgColor: "#4B68AE",
    buttonTextColor: "#FFF",
  } as LoginConfigItem,
} as LoginConfig;

export const validatePaymentProvider = (provider: string, params: PaymentParams): { errors: PaymentErrors; isValid: boolean } => {
  const errors: PaymentErrors = {};

  if (!provider) {
    return { errors, isValid: true };
  }

  if (provider && !paymentProviders[provider]) {
    errors.provider = "Invalid Provider";
    return { errors, isValid: Object.keys(errors).length === 0 };
  }

  const selectedProvider = paymentProviders[provider as PAYMENT_PROVIDER_TYPE];
  const selectedParams = params || {};

  // set default values
  // if (!selectedParams.selectedCurrency) [selectedParams.selectedCurrency] = selectedProvider.validCurrencies
  // if (!selectedParams.fiatValue) selectedParams.fiatValue = selectedProvider.minOrderValue
  // if (!selectedParams.selectedCryptoCurrency) [selectedParams.selectedCryptoCurrency] = selectedProvider.validCryptoCurrencies

  // validations
  if (selectedParams.fiatValue) {
    const requestedOrderAmount = +parseFloat(selectedParams.fiatValue.toString()) || 0;
    if (requestedOrderAmount < selectedProvider.minOrderValue) errors.fiatValue = "Requested amount is lower than supported";
    if (requestedOrderAmount > selectedProvider.maxOrderValue && selectedProvider.enforceMax)
      errors.fiatValue = "Requested amount is higher than supported";
  }
  if (selectedParams.selectedCurrency && !selectedProvider.validCurrencies.includes(selectedParams.selectedCurrency)) {
    errors.selectedCurrency = "Unsupported currency";
  }
  if (selectedParams.selectedCryptoCurrency) {
    const validCryptoCurrenciesByChain = Object.values(selectedProvider.validCryptoCurrenciesByChain)
      .flat()
      .map((currency) => currency.value);

    const finalCryptoCurrency =
      provider === PAYMENT_PROVIDER.MOONPAY ? selectedParams.selectedCryptoCurrency.toLowerCase() : selectedParams.selectedCryptoCurrency;

    if (validCryptoCurrenciesByChain && !validCryptoCurrenciesByChain.includes(finalCryptoCurrency))
      errors.selectedCryptoCurrency = "Unsupported cryptoCurrency";
  }
  return { errors, isValid: Object.keys(errors).length === 0 };
};

// utility functions

/**
 * json-rpc-engine middleware that logs RPC errors and and validates req.method.
 *
 * @param log - The logging API to use.
 * @returns  json-rpc-engine middleware function
 */
export function createErrorMiddleware(): JRPCMiddleware<unknown, unknown> {
  return (req, res, next) => {
    // json-rpc-engine will terminate the request when it notices this error
    if (typeof req.method !== "string" || !req.method) {
      res.error = ethErrors.rpc.invalidRequest({
        message: `The request 'method' must be a non-empty string.`,
        data: req,
      });
    }

    next((done) => {
      const { error } = res;
      if (!error) {
        return done();
      }
      log.error(`MetaMask - RPC Error: ${error.message}`, error);
      return done();
    });
  };
}

// resolve response.result or response, reject errors
export const getRpcPromiseCallback =
  (resolve: (value?: any) => void, reject: (error?: Error) => void, unwrapResult = true) =>
  (error: Error, response: PendingJRPCResponse<unknown>): void => {
    if (error || response.error) {
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      reject(error || response.error);
    } else {
      resolve(!unwrapResult || Array.isArray(response) ? response : response.result);
    }
  };

/**
 * Logs a stream disconnection error. Emits an 'error' if given an
 * EventEmitter that has listeners for the 'error' event.
 *
 * @param log - The logging API to use.
 * @param remoteLabel - The label of the disconnected stream.
 * @param error - The associated error to log.
 * @param emitter - The logging API to use.
 */
export function logStreamDisconnectWarning(remoteLabel: string, error: Error, emitter: SafeEventEmitter): void {
  let warningMsg = `MetaMask: Lost connection to "${remoteLabel}".`;
  if (error?.stack) {
    warningMsg += `\n${error.stack}`;
  }
  log.warn(warningMsg);
  if (emitter && emitter.listenerCount("error") > 0) {
    emitter.emit("error", warningMsg);
  }
}

export const getPreopenInstanceId = () => Math.random().toString(36).slice(2);

export const getUpbondWalletUrl = async (
  buildEnv: UPBOND_BUILD_ENV_TYPE,
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  integrity: IntegrityParams
): Promise<{ torusUrl: string; logLevel: LogLevelDesc }> => {
  log.info("Opening torus URL!");
  let torusUrl: string;
  let logLevel: LogLevelDesc;
  // log.info("version used: ", versionUsed);
  switch (buildEnv) {
    /*
    Default the default to v2
    */
    case "production":
    case "v1_production":
    case "v2_production":
      torusUrl = `https://login.upbond.io`;
      logLevel = "info";
      break;
    case "staging":
    case "v1_staging":
    case "v2_staging":
      torusUrl = "https://login.stg.upbond.io";
      logLevel = "info";
      break;
    case "development":
    case "v1_development":
    case "v2_development":
    case "testing":
      torusUrl = "https:/login.dev.upbond.io";
      logLevel = "debug";
      break;
    case "local":
    case "v2_local":
      torusUrl = "http://localhost:3002";
      logLevel = "debug";
      break;
    case "wallet-did":
      torusUrl = "https://wallet-did.dev.upbond.io";
      logLevel = "debug";
      break;
    case "mpc-dev":
    case "v3_development":
      torusUrl = "https://login-mpc.dev.upbond.io";
      logLevel = "debug";
      break;
    case "v3_staging":
      torusUrl = "https://login-mpc.stg.upbond.io";
      logLevel = "debug";
      break;
    case "v3_production":
      torusUrl = "https://login3.upbond.io";
      logLevel = "info";
      break;
    default:
      torusUrl = `https://login.upbond.io`;
      logLevel = "info";
      break;
  }
  return { torusUrl, logLevel };
};

export const getUserLanguage = (): string => {
  let userLanguage = window.navigator.language || "en-US";
  const userLanguages = userLanguage.split("-");
  userLanguage = Object.prototype.hasOwnProperty.call(config.translations, userLanguages[0]) ? userLanguages[0] : "en";
  return userLanguage;
};

export const EMITTED_NOTIFICATIONS = [
  "eth_subscription", // per eth-json-rpc-filters/subscriptionManager
];

export const NOOP = (): void => {
  // empty function
};

export const FEATURES_PROVIDER_CHANGE_WINDOW = "directories=0,titlebar=0,toolbar=0,status=0,location=0,menubar=0,height=660,width=375";
export const FEATURES_DEFAULT_WALLET_WINDOW = "directories=0,titlebar=0,toolbar=0,status=0,location=0,menubar=0,height=740,width=1315";
export const FEATURES_DEFAULT_POPUP_WINDOW = "directories=0,titlebar=0,toolbar=0,status=0,location=0,menubar=0,height=700,width=1200";
export const FEATURES_CONFIRM_WINDOW = "directories=0,titlebar=0,toolbar=0,status=0,location=0,menubar=0,height=700,width=450";

export function getPopupFeatures(): string {
  // Fixes dual-screen position                             Most browsers      Firefox
  const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : window.screenX;
  const dualScreenTop = window.screenTop !== undefined ? window.screenTop : window.screenY;

  const w = 1200;
  const h = 700;

  const width = window.innerWidth
    ? window.innerWidth
    : document.documentElement.clientWidth
    ? document.documentElement.clientWidth
    : window.screen.width;

  const height = window.innerHeight
    ? window.innerHeight
    : document.documentElement.clientHeight
    ? document.documentElement.clientHeight
    : window.screen.height;

  const systemZoom = 1; // No reliable estimate

  const left = Math.abs((width - w) / 2 / systemZoom + dualScreenLeft);
  const top = Math.abs((height - h) / 2 / systemZoom + dualScreenTop);
  const features = `titlebar=0,toolbar=0,status=0,location=0,menubar=0,height=${h / systemZoom},width=${w / systemZoom},top=${top},left=${left}`;
  return features;
}

export const searchToObject = <T>(search): T => {
  return search
    .substring(1)
    .split("&")
    .reduce(function (result, value) {
      const parts = value.split("=");
      if (parts[0]) result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
      return result as T;
    }, {});
};

export const parseIdToken = (token, pureJwt = false) => {
  if (pureJwt) {
    const json = decodeURIComponent(
      window
        .atob(token)
        .split("")
        .map((c) => {
          return `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`;
        })
        .join("")
    );
    return JSON.parse(json);
  }
  const base64Url = token.split(".")[1];
  const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
  const jsonPayload = decodeURIComponent(
    window
      .atob(base64)
      .split("")
      .map((c) => {
        return `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`;
      })
      .join("")
  );

  return JSON.parse(jsonPayload);
};
