import isEmpty from 'lodash/isEmpty';

import { Op } from 'sequelize';
import { CheckoutSession, PaymentCurrency, PaymentMethod, Price, Product, Subscription } from '../store/models';
import { EVM_CHAIN_TYPES } from './constants';
import { getApproveFunction } from '../integrations/ethereum/contract';

export async function getMainProductName(subscriptionId: string): Promise<string> {
  const subscription = await Subscription.findByPk(subscriptionId);

  // @see: https://github.com/ArcBlock/did-spaces/issues/962#issuecomment-1880549421
  if (subscription && !isEmpty(subscription.description)) {
    return subscription.description!;
  }

  const checkoutSession = await CheckoutSession.findBySubscriptionId(subscriptionId, {
    attributes: ['line_items'],
  });
  const priceId: string = checkoutSession?.line_items.find((x) => !x.cross_sell)?.price_id as string;

  if (!priceId) {
    throw new Error(`PriceId can't be found by subscriptionId(${subscriptionId})`);
  }

  const price = await Price.findByPk(priceId, {
    attributes: ['product_id'],
  });

  if (!price) {
    throw new Error(`Price can't be found by priceId(${priceId})`);
  }

  const product = await Product.findByPk(price?.product_id);

  if (!product) {
    throw new Error(`Product can't be found by productId(${price?.product_id})`);
  }

  return product.name;
}

export async function getMainProductNameByCheckoutSession(checkoutSession: CheckoutSession): Promise<string> {
  const priceId: string = checkoutSession?.line_items.find((x) => !x.cross_sell)?.price_id as string;

  if (!priceId) {
    throw new Error(`PriceId can't be found by checkoutSession(${checkoutSession.id})`);
  }

  const price = await Price.findByPk(priceId, {
    attributes: ['product_id'],
  });

  if (!price) {
    throw new Error(`Price can't be found by priceId(${priceId})`);
  }

  const product = await Product.findByPk(price?.product_id);

  if (!product) {
    throw new Error(`Product can't be found by productId(${price?.product_id})`);
  }

  return product.name;
}

export async function checkCurrencySupportRecurring(currencyIds: string[] | string, isRecurring: boolean) {
  if (!isRecurring) {
    return {
      notSupportCurrencies: [],
      validate: true,
    };
  }
  const currencyIdsArray = Array.isArray(currencyIds) ? currencyIds : [currencyIds];
  const currencies = (await PaymentCurrency.findAll({
    where: { id: { [Op.in]: currencyIdsArray } },
    include: [{ model: PaymentMethod, as: 'payment_method' }],
  })) as (PaymentCurrency & { payment_method: PaymentMethod })[];

  const notSupportCurrencies = (
    await Promise.all(
      currencies.map(async (currency) => {
        const paymentMethod = currency.payment_method;
        if (!paymentMethod) return null;

        if (EVM_CHAIN_TYPES.includes(paymentMethod.type) && paymentMethod.default_currency_id === currency.id) {
          return currency;
        }

        if (['ethereum', 'base'].includes(paymentMethod.type) && currency.contract) {
          try {
            const provider = paymentMethod.getEvmClient();
            await getApproveFunction(provider, currency.contract);
            return null;
          } catch (err) {
            return currency;
          }
        }

        return null;
      })
    )
  ).filter((c) => c !== null);

  return {
    notSupportCurrencies,
    validate: notSupportCurrencies.length === 0,
  };
}
