/* eslint-disable @typescript-eslint/brace-style */
/* eslint-disable @typescript-eslint/indent */
import { toDid } from '@ocap/util';
import pWaitFor from 'p-wait-for';
import isEmpty from 'lodash/isEmpty';

import { translate } from '../../../locales';
import { CheckoutSession, NFTMintChainType, NftMintItem } from '../../../store/models';
import { getOneTimeProductInfo } from '../../invoice';
import { formatTime } from '../../time';
import { BaseSubscriptionEmailTemplate, BaseEmailTemplateType } from './base';

export interface SubscriptionTrialStartEmailTemplateOptions {
  subscriptionId: string;
}

interface OneTimeProductInfo {
  paymentInfo: string;
  productName: string;
  quantity: number;
}

interface SubscriptionTrialStartEmailTemplateContext {
  locale: string;
  productName: string;
  subscriptionTrialEnd: string;

  nftMintItem: NftMintItem | undefined;
  chainHost: string | undefined;
  userDid: string;
  paymentInfo: string;
  currentPeriodStart: string;
  currentPeriodEnd: string;
  duration: string;

  viewSubscriptionLink: string;
  viewInvoiceLink: string;
  oneTimeProductInfo?: Array<OneTimeProductInfo>;
  customActions: any[];
  isCreditSubscription: boolean;
}

export class SubscriptionTrialStartEmailTemplate extends BaseSubscriptionEmailTemplate<SubscriptionTrialStartEmailTemplateContext> {
  options: SubscriptionTrialStartEmailTemplateOptions;

  constructor(options: SubscriptionTrialStartEmailTemplateOptions) {
    super();
    this.options = options;
  }

  async getContext(): Promise<SubscriptionTrialStartEmailTemplateContext> {
    // 获取基础订阅数据
    const basicData = await this.getSubscriptionBasicData(this.options.subscriptionId);
    const { subscription, userDid, locale, productName, paymentCurrency, isCreditSubscription } = basicData;

    if (subscription.status !== 'trialing') {
      throw new Error(`Subscription not trialing: ${this.options.subscriptionId}`);
    }

    // 等待 NFT 铸造完成
    await pWaitFor(
      async () => {
        const checkoutSession = await CheckoutSession.findBySubscriptionId(subscription.id);
        return ['minted', 'sent', 'error', 'disabled'].includes(checkoutSession?.nft_mint_status as string);
      },
      { timeout: 1000 * 10, interval: 1000 }
    );

    // 获取 NFT 和支付信息
    const paymentInfoResult = await this.getPaymentInfo(
      subscription,
      paymentCurrency,
      isCreditSubscription,
      subscription.latest_invoice_id
    );
    const oneTimeProductInfo = await getOneTimeProductInfo(subscription.latest_invoice_id as string, paymentCurrency);

    const checkoutSession = await CheckoutSession.findBySubscriptionId(subscription.id);
    const hasNft = checkoutSession?.nft_mint_status === 'minted';
    const nftMintItem = hasNft
      ? checkoutSession?.nft_mint_details?.[checkoutSession?.nft_mint_details?.type as NFTMintChainType]
      : undefined;
    const chainHost =
      paymentInfoResult.paymentMethod?.settings?.[checkoutSession?.nft_mint_details?.type as NFTMintChainType]
        ?.api_host;

    // 获取链接
    const links = this.generateSubscriptionLinks(
      subscription,
      locale,
      userDid,
      'customer.subscription.trial_start',
      subscription.latest_invoice_id,
      isCreditSubscription
    );

    // 计算时间信息
    const subscriptionTrialEnd = formatTime((subscription.trial_end as number) * 1000);
    const periodInfo = this.formatSubscriptionPeriod(
      subscription.trial_start as number,
      subscription.trial_end as number,
      locale
    );

    return {
      locale,
      productName,
      subscriptionTrialEnd,
      nftMintItem,
      chainHost,
      userDid,
      paymentInfo: '0',
      currentPeriodStart: periodInfo.currentPeriodStart,
      currentPeriodEnd: periodInfo.currentPeriodEnd,
      duration: periodInfo.duration,
      viewSubscriptionLink: links.viewSubscriptionLink,
      viewInvoiceLink: links.viewInvoiceLink!,
      oneTimeProductInfo,
      customActions: links.customActions,
      isCreditSubscription,
    };
  }

  private getOneTimeProductTemplate(oneTimeProductInfo: Array<OneTimeProductInfo>, locale: string = 'en') {
    return [
      {
        type: 'divider',
      },
      {
        type: 'text',
        data: {
          type: 'plain',
          text: translate('notification.common.expandPayment', locale),
        },
      },
      {
        type: 'section',
        fields: (oneTimeProductInfo || []).flatMap((x: any) => [
          {
            type: 'text',
            data: {
              type: 'plain',
              color: '#9397A1',
              text: translate('notification.common.product', locale),
            },
          },
          {
            type: 'text',
            data: {
              type: 'plain',
              text: x?.productName,
            },
          },
          {
            type: 'text',
            data: {
              type: 'plain',
              color: '#9397A1',
              text: translate('notification.common.paymentAmount', locale),
            },
          },
          {
            type: 'text',
            data: {
              type: 'plain',
              text: x?.paymentInfo,
            },
          },
          {
            type: 'text',
            data: {
              type: 'plain',
              color: '#9397A1',
              text: translate('notification.common.paymentQuantity', locale),
            },
          },
          {
            type: 'text',
            data: {
              type: 'plain',
              text: translate('notification.common.qty', locale, {
                count: x.quantity,
              }),
            },
          },
        ]),
      },
    ];
  }

  async getTemplate(): Promise<BaseEmailTemplateType> {
    const context = await this.getContext();
    const {
      locale,
      productName,
      subscriptionTrialEnd,
      nftMintItem,
      chainHost,
      userDid,
      currentPeriodStart,
      currentPeriodEnd,
      duration,
      viewSubscriptionLink,
      viewInvoiceLink,
      oneTimeProductInfo,
      customActions,
      isCreditSubscription,
    } = context;

    const hasOneTimeProduct = !isEmpty(oneTimeProductInfo);

    // 构建字段
    const commonFields = this.buildCommonFields(userDid, productName, locale);

    // 试用期字段
    const trialPeriodFields = isCreditSubscription
      ? []
      : [
          {
            type: 'text',
            data: {
              type: 'plain',
              color: '#9397A1',
              text: translate('notification.common.trialPeriod', locale),
            },
          },
          {
            type: 'text',
            data: {
              type: 'plain',
              text: `${currentPeriodStart} ~ ${currentPeriodEnd}(${duration})`,
            },
          },
        ];

    // NFT 地址字段
    const nftFields = nftMintItem
      ? [
          {
            type: 'text',
            data: {
              type: 'plain',
              color: '#9397A1',
              text: translate('notification.common.nftAddress', locale),
            },
          },
          {
            type: 'text',
            data: {
              type: 'plain',
              text: toDid(nftMintItem.address),
            },
          },
        ]
      : [];

    // 构建附件
    const attachments = [
      nftMintItem &&
        chainHost && {
          type: 'asset',
          data: {
            chainHost,
            did: nftMintItem.address,
          },
        },
      hasOneTimeProduct && {
        type: 'text',
        data: {
          type: 'plain',
          text: translate('notification.common.trialProduct', locale),
        },
      },
      {
        type: 'section',
        fields: [...commonFields, ...trialPeriodFields, ...nftFields].filter(Boolean),
      },
      ...(hasOneTimeProduct
        ? this.getOneTimeProductTemplate(oneTimeProductInfo as Array<OneTimeProductInfo>, locale)
        : []),
    ].filter(Boolean);

    // 构建操作按钮
    const actions = [
      {
        name: translate('notification.common.viewSubscription', locale),
        title: translate('notification.common.viewSubscription', locale),
        link: viewSubscriptionLink,
      },
      {
        name: translate('notification.common.viewInvoice', locale),
        title: translate('notification.common.viewInvoice', locale),
        link: viewInvoiceLink,
      },
      ...customActions,
    ].filter(Boolean);

    const template: BaseEmailTemplateType = {
      title: translate('notification.subscriptionTrialStart.title', locale, {
        productName,
      }),
      body: translate('notification.subscriptionTrialStart.body', locale, {
        subscriptionTrialEnd,
        productName,
        trialDuration: duration,
      }),
      // @ts-expect-error
      attachments,
      // @ts-ignore
      actions,
    };

    return template;
  }
}
