/* eslint-disable no-continue */
/* eslint-disable no-await-in-loop */
/* eslint-disable no-console */
import fs from 'fs';
import path from 'path';

import { getPackResources, getResources } from '@blocklet/sdk/lib/component';
import { env } from '@blocklet/sdk/lib/config';
import { fromTokenToUnit } from '@ocap/util';

import { updatePassportExtra } from '../integrations/blocklet/passport';
import { replace } from '../locales';
import { createPaymentLink } from '../routes/payment-links';
import { createPrice } from '../routes/prices';
import { createProductAndPrices } from '../routes/products';
import { PaymentCurrency, PaymentLink, Price, Product, nextPriceId } from '../store/models';

export async function getPackResource(type: string) {
  try {
    const resources = await getPackResources({
      types: [
        {
          did: env.componentDid,
          type,
        },
      ],
    });

    if (resources) {
      return resources[0] || null;
    }

    return null;
  } catch (error) {
    console.error(`failed to get ${type} pack resource from ${env.componentDid}`, error);
    return null;
  }
}

export async function getResourcesByType(type: string) {
  try {
    const pack = await getPackResource(type);
    const resources = await getResources({ types: [{ did: env.componentDid, type }], skipRunningCheck: true });
    return pack ? [pack, ...resources] : resources;
  } catch (error) {
    console.error(`failed to get ${type} resources from ${env.componentDid}`, error);
    return [];
  }
}

export async function initPaywallResources() {
  const resources = await getResourcesByType('paywall');
  if (!resources.length) {
    console.info('No paywall resource found');
    return;
  }

  // TODO: use schema validation
  for (const resource of resources) {
    const configPath = resource.path;
    try {
      console.info('try import paywall resource', resource);

      const config: any = JSON.parse(
        replace(fs.readFileSync(path.join(configPath!, 'config.json'), 'utf8'), {
          ...env,
          monthPrice: resource.env?.MONTH_PRICE || '5',
          yearPrice: resource.env?.YEAR_PRICE || '30',
          passport: resource.env?.PASSPORT_NAME || 'discussionSubscriber',
        })
      );
      console.info('try import paywall config', config);

      if (!config.passport) {
        console.warn(`invalid paywall resource from ${configPath}: passport empty`);
        continue;
      }
      if (!config.product) {
        console.warn(`invalid paywall resource from ${configPath}: product empty`);
        continue;
      }
      if (!config.product.price) {
        console.warn(`invalid paywall resource from ${configPath}: product price empty`);
        continue;
      }

      const metadata = { source: resource.did, passport: config.passport };
      const currency = await PaymentCurrency.findOne({
        where: { is_base_currency: true, livemode: config.product.livemode },
      });
      if (!currency) {
        console.warn(`invalid paywall resource from ${configPath}: base currency not found`);
        continue;
      }

      const existProduct = await Product.findOne({
        where: { 'metadata.source': resource.did },
        include: [{ model: Price, as: 'prices', order: [['created_at', 'DESC']] }],
      });
      if (existProduct) {
        console.warn(`paywall resource already imported from path: ${configPath}`);

        await existProduct.update({
          name: config.product.name,
          description: config.product.description,
          metadata,
        });

        // @ts-ignore
        const monthPrice = existProduct.prices.find(
          // @ts-ignore
          (price) =>
            price.nickname === 'monthly-member-price' &&
            price.unit_amount === fromTokenToUnit(config.product.price.month, currency.decimal).toString()
        );
        // @ts-ignore
        const yearPrice = existProduct.prices.find(
          // @ts-ignore
          (price) =>
            price.nickname === 'yearly-member-price' &&
            price.unit_amount === fromTokenToUnit(config.product.price.year, currency.decimal).toString()
        );

        let newMonthPriceId = '';
        if (!monthPrice) {
          newMonthPriceId = nextPriceId();
          await createPrice({
            id: newMonthPriceId,
            product_id: existProduct.id,
            type: 'recurring',
            model: 'standard',
            nickname: 'monthly-member-price',
            unit_amount: +config.product.price.month,
            currency_id: currency.id,
            recurring: {
              interval: 'month',
              interval_count: 1,
              usage_type: 'licensed',
            },
            metadata,
          });
          console.warn(`paywall resource month price recreated from path: ${configPath}`);
        }

        let newYearPriceId = '';
        if (!yearPrice) {
          newYearPriceId = nextPriceId();
          await createPrice({
            id: newYearPriceId,
            product_id: existProduct.id,
            type: 'recurring',
            model: 'standard',
            nickname: 'yearly-member-price',
            unit_amount: +config.product.price.year,
            currency_id: currency.id,
            recurring: {
              interval: 'year',
              interval_count: 1,
              usage_type: 'licensed',
            },
            metadata,
          });
          console.warn(`paywall resource year price recreated from path: ${configPath}`);
        }

        // update upsell relation
        console.warn(`paywall resource upsell recreated from path: ${configPath}`);
        await Price.update(
          { upsell: { upsells_to_id: newYearPriceId || yearPrice.id } },
          { where: { id: newMonthPriceId || monthPrice.id } }
        );

        // Create another payment link and redo updatePassportExtra
        if (newMonthPriceId) {
          await Product.update({ default_price_id: newMonthPriceId }, { where: { id: existProduct.id }, limit: 1 });

          const link = await createPaymentLink({
            name: `Paywall for membership of ${config.product.name}`,
            livemode: config.product.livemode,
            currency_id: currency.id,
            line_items: [
              {
                price_id: newMonthPriceId,
                quantity: 1,
              },
            ],
            metadata,
          });
          console.info('payment link recreated for paywall resource', { link: link.id });

          await updatePassportExtra(config.passport, {
            payment: { product: existProduct.id },
            acquire: { pay: link.id },
          });
          console.info('product and payment link reassociated with passport');
        } else {
          const existLink = await PaymentLink.findOne({ where: { 'metadata.source': resource.did } });
          if (existLink) {
            await updatePassportExtra(config.passport, {
              payment: { product: existProduct.id },
              acquire: { pay: existLink.id },
            });
          }
          console.info('product and payment link associated with passport again');
        }
      } else {
        const monthPriceId = nextPriceId();
        const yearPriceId = nextPriceId();

        const product = await createProductAndPrices({
          name: config.product.name,
          type: 'service',
          description: config.product.description,
          livemode: config.product.livemode,
          images: [],
          features: [],
          metadata,
          prices: [
            {
              id: monthPriceId,
              type: 'recurring',
              model: 'standard',
              nickname: 'monthly-member-price',
              unit_amount: +config.product.price.month,
              currency_id: currency.id,
              recurring: {
                interval: 'month',
                interval_count: 1,
                usage_type: 'licensed',
              },
              upsell: config.product.price.upsell ? { upsells_to_id: yearPriceId } : undefined,
              metadata,
            },
            {
              id: yearPriceId,
              type: 'recurring',
              model: 'standard',
              nickname: 'yearly-member-price',
              unit_amount: +config.product.price.year,
              currency_id: currency.id,
              recurring: {
                interval: 'year',
                interval_count: 1,
                usage_type: 'licensed',
              },
              metadata,
            },
          ],
        });
        console.info('product created for paywall resource', { product: product.id });

        const link = await createPaymentLink({
          name: `Paywall for membership of ${config.product.name}`,
          livemode: config.product.livemode,
          currency_id: currency.id,
          line_items: [
            {
              price_id: monthPriceId,
              quantity: 1,
            },
          ],
          metadata,
        });
        console.info('payment link created for paywall resource', { link: link.id });

        await updatePassportExtra(config.passport, {
          payment: { product: product.id },
          acquire: { pay: link.id },
        });
        console.info('product and payment link associated with passport');
      }
      console.info(`paywall resource successfully imported from path: ${configPath}`);
    } catch (err) {
      console.error(`failed to import paywall resource from ${configPath}`, err);
    }
  }
}
