/* eslint-disable @typescript-eslint/brace-style */
/* eslint-disable @typescript-eslint/indent */
import type { ManipulateType } from 'dayjs';
import type { LiteralUnion } from 'type-fest';

import dayjs from '../../dayjs';
import { getTokenByAddress } from '../../../integrations/arcblock/stake';
import { translate } from '../../../locales';
import { Invoice, Price, SubscriptionItem } from '../../../store/models';
import type { PaymentDetail } from '../../payment';
import { getSubscriptionPaymentAddress, getEstimatedPaymentAmountForCycleSubscription } from '../../subscription';

import { formatTime, getSimplifyDuration } from '../../time';
import { formatCurrencyInfo, formatTokenAmount, getCustomerRechargeLink } from '../../util';
import { BaseSubscriptionEmailTemplate, BaseEmailTemplateType } from './base';

export interface SubscriptionWillRenewEmailTemplateOptions {
  subscriptionId: string;
  willRenewValue: number;
  willRenewUnit: ManipulateType;
  required?: false | true;
}

interface SubscriptionWillRenewEmailTemplateContext {
  locale: string;
  productName: string;
  at: string;
  willRenewDuration: string;
  paymentDetail: PaymentDetail;
  paidType: string;
  userDid: string;
  paymentInfo: string;
  currentPeriodStart: string;
  currentPeriodEnd: string;
  duration: string;
  viewSubscriptionLink: string;
  addFundsLink: string;
  customActions: any[];
  isCreditSubscription: boolean;
  isStripe: boolean;
  isMetered: boolean;
  payer: string;
}

export class SubscriptionWillRenewEmailTemplate extends BaseSubscriptionEmailTemplate<SubscriptionWillRenewEmailTemplateContext> {
  options: SubscriptionWillRenewEmailTemplateOptions;

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

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

    if (subscription.isActive() === false) {
      throw new Error(`Subscription not active: ${this.options.subscriptionId}`);
    }
    if (subscription.isScheduledToCancel()) {
      throw new Error(`Subscription is scheduled to cancel: ${this.options.subscriptionId}`);
    }
    if (this.subscriptionIsRenewed(subscription)) {
      throw new Error(`The subscription(${this.options.subscriptionId}) has been renewed`);
    }

    const invoice = await Invoice.findByPk(subscription.latest_invoice_id);

    // 获取支付信息
    const paymentInfoResult = await this.getPaymentInfo(
      subscription,
      paymentCurrency,
      isCreditSubscription,
      invoice?.id
    );

    // 获取链接
    const links = this.generateSubscriptionLinks(
      subscription,
      locale,
      userDid,
      'customer.subscription.will_renew',
      invoice?.id,
      isCreditSubscription
    );

    // 计算时间和支付详情 - 使用invoice的period_end，如果不存在则使用subscription的current_period_end
    const periodEnd = invoice?.period_end || subscription.current_period_end;
    const at = formatTime(periodEnd * 1000);
    const willRenewDuration = getSimplifyDuration((periodEnd - dayjs().unix()) * 1000, locale);

    const paymentAmountResult = await getEstimatedPaymentAmountForCycleSubscription(subscription, paymentCurrency);
    const paymentAmount = paymentAmountResult.amount;
    const paymentDetail = { price: paymentAmount, balance: 0, symbol: paymentCurrency.symbol, balanceFormatted: '0' };

    // 获取余额信息（非 Stripe 支付方式）
    const isStripe = paymentInfoResult.paymentMethod?.type === 'stripe';
    if (!isStripe && !isCreditSubscription) {
      const paymentAddress = getSubscriptionPaymentAddress(subscription, paymentInfoResult.paymentMethod!.type);
      const balance = await getTokenByAddress(paymentAddress, paymentInfoResult.paymentMethod!, paymentCurrency);

      paymentDetail.balanceFormatted = formatTokenAmount(balance || '0', paymentCurrency.decimal);
      paymentDetail.balance = +paymentDetail.balanceFormatted;
    }

    // 获取支付类型和周期信息
    const { isPrePaid, interval } = await this.getPaymentCategory(subscription.id);
    const isMetered = !isPrePaid; // 按量计费就是后付费

    const paidType = isPrePaid
      ? translate('notification.common.prepaid', locale)
      : translate('notification.common.postpaid', locale);

    // 对于按量计费，在金额后添加预估说明
    const basePaymentInfo = formatCurrencyInfo(
      paymentDetail?.price || '0',
      paymentCurrency,
      paymentInfoResult.paymentMethod,
      true
    );

    // Determine payment info message based on estimation type
    let paymentInfo: string;
    if (paymentAmountResult.estimatedByRate && isMetered) {
      paymentInfo = translate('notification.subscriptionWillRenew.estimatedAmountNoteRateAndUsage', locale, {
        amount: basePaymentInfo,
      });
    } else if (paymentAmountResult.estimatedByRate) {
      paymentInfo = translate('notification.subscriptionWillRenew.estimatedAmountNoteRate', locale, {
        amount: basePaymentInfo,
      });
    } else if (isMetered) {
      paymentInfo = translate('notification.subscriptionWillRenew.estimatedAmountNote', locale, {
        amount: basePaymentInfo,
      });
    } else {
      paymentInfo = basePaymentInfo;
    }

    // 计算周期时间 - 使用安全的回退机制
    const periodStart = invoice?.period_start || subscription.current_period_start;
    const periodInfo = this.formatSubscriptionPeriod(
      isPrePaid ? periodEnd : periodStart,
      isPrePaid
        ? dayjs(periodEnd * 1000)
            .add(1, interval as ManipulateType)
            .unix()
        : periodEnd,
      locale
    );

    const addFundsLink = getCustomerRechargeLink({
      locale,
      userDid,
      subscriptionId: subscription.id,
    });

    return {
      locale,
      productName,
      at,
      willRenewDuration,
      paymentDetail,
      paidType,
      userDid,
      paymentInfo,
      currentPeriodStart: periodInfo.currentPeriodStart,
      currentPeriodEnd: periodInfo.currentPeriodEnd,
      duration: periodInfo.duration,
      viewSubscriptionLink: links.viewSubscriptionLink,
      addFundsLink,
      customActions: links.customActions,
      isCreditSubscription,
      isStripe,
      isMetered: !isPrePaid,
      payer:
        paymentInfoResult.paymentMethod?.type !== 'stripe' &&
        getSubscriptionPaymentAddress(subscription, paymentInfoResult.paymentMethod!.type),
    };
  }

  private async getPaymentCategory(subscriptionId: string): Promise<{
    isPrePaid: boolean;
    interval: LiteralUnion<'hour' | 'day' | 'week' | 'month' | 'year', string> | undefined;
  }> {
    const subscriptionItems = await SubscriptionItem.findAll({
      where: { subscription_id: subscriptionId },
    });

    const lineItemExpanded = await Price.expand(subscriptionItems);
    const metered = lineItemExpanded.find((lineItem) => lineItem.price.recurring?.usage_type === 'metered');
    const recurringItems = lineItemExpanded.filter((lineItem) => lineItem.price.type === 'recurring');

    return {
      isPrePaid: !metered,
      interval: recurringItems?.[0]?.price.recurring?.interval,
    };
  }

  private subscriptionIsRenewed(subscription: any): boolean {
    const expectedCurrentPeriodEnd = dayjs()
      .add(this.options.willRenewValue + 1, this.options.willRenewUnit)
      .toDate()
      .getTime();
    const currentPeriodEnd = subscription.current_period_end * 1000;

    return currentPeriodEnd > expectedCurrentPeriodEnd;
  }

  async getTemplate(): Promise<BaseEmailTemplateType | null> {
    const context = await this.getContext();
    const {
      locale,
      productName,
      at,
      willRenewDuration,
      paymentDetail,
      paidType,
      userDid,
      paymentInfo,
      currentPeriodStart,
      currentPeriodEnd,
      duration,
      viewSubscriptionLink,
      addFundsLink,
      customActions,
      isCreditSubscription,
      isStripe,
      isMetered,
      payer,
    } = context;

    // 如果当前时间大于预计扣费时间，那么不发送通知
    if (dayjs().utc().isAfter(dayjs.utc(at))) {
      return null;
    }

    const canPay = paymentDetail.balance >= paymentDetail.price;
    // 如果是按量付费的预估金额，余额充足，不发送通知
    // 如果是预付费，余额充足，非必要不发送通知
    if (canPay && (!this.options.required || isMetered)) {
      return null;
    }

    if (!paymentDetail.price && paymentDetail.symbol !== 'USD') {
      return null;
    }

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

    // 续费金额字段
    const renewAmountFields = isCreditSubscription
      ? []
      : [
          {
            type: 'text',
            data: {
              type: 'plain',
              color: '#9397A1',
              text: translate('notification.subscriptionWillRenew.renewAmount', locale),
            },
          },
          {
            type: 'text',
            data: {
              type: 'plain',
              text: paymentInfo,
            },
          },
        ];

    // 当前余额字段（非 Stripe 时显示）
    const balanceFields =
      !isStripe && !isCreditSubscription
        ? [
            {
              type: 'text',
              data: {
                type: 'plain',
                color: '#9397A1',
                text: translate('notification.common.currentBalance', locale),
              },
            },
            {
              type: 'text',
              data: {
                type: 'plain',
                ...(!canPay && { color: '#FF0000' }),
                text: `${paymentDetail.balanceFormatted} ${paymentDetail.symbol}`,
              },
            },
          ]
        : [];

    // 余额不足提醒字段
    const insufficientBalanceFields =
      !canPay && !isStripe && !isCreditSubscription
        ? [
            {
              type: 'text',
              data: {
                type: 'plain',
                color: '#9397A1',
                text: translate('notification.common.balanceReminder', locale),
              },
            },
            {
              type: 'text',
              data: {
                type: 'plain',
                color: '#FF0000',
                text: translate('notification.subscriptionWillRenew.unableToPayReason', locale, {
                  balance: `${paymentDetail.balance} ${paymentDetail.symbol}`,
                  price: `${paymentDetail.price} ${paymentDetail.symbol}`,
                }),
              },
            },
          ]
        : [];

    // 支付类型字段
    const paidTypeFields = isCreditSubscription
      ? []
      : [
          {
            type: 'text',
            data: {
              type: 'plain',
              color: '#9397A1',
              text: translate('notification.common.paidType', locale),
            },
          },
          {
            type: 'text',
            data: {
              type: 'plain',
              text: paidType,
            },
          },
        ];

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

    // 构建操作按钮
    const actions = [
      !canPay &&
        !isStripe &&
        !isCreditSubscription &&
        addFundsLink && {
          name: translate('notification.common.addFunds', locale),
          title: translate('notification.common.addFunds', locale),
          link: addFundsLink,
        },
      {
        name: translate('notification.common.viewSubscription', locale),
        title: translate('notification.common.viewSubscription', locale),
        link: viewSubscriptionLink,
      },
      ...customActions,
    ].filter(Boolean);

    const template: BaseEmailTemplateType = {
      title: translate('notification.subscriptionWillRenew.title', locale, {
        productName,
        willRenewDuration,
      }),
      body:
        canPay || isStripe
          ? translate('notification.subscriptionWillRenew.body', locale, {
              at,
              productName,
              willRenewDuration,
              balance: `${paymentDetail.balanceFormatted} ${paymentDetail.symbol}`,
            })
          : translate('notification.subscriptionWillRenew.unableToPayBody', locale, {
              at,
              productName,
              willRenewDuration,
            }),
      // @ts-expect-error
      attachments: [
        {
          type: 'section',
          fields: [
            ...commonFields,
            ...(payer
              ? [
                  {
                    type: 'text',
                    data: {
                      type: 'plain',
                      color: '#9397A1',
                      text: translate('notification.common.payer', locale),
                    },
                  },
                  {
                    type: 'text',
                    data: {
                      type: 'plain',
                      text: payer,
                    },
                  },
                ]
              : []),
            ...renewAmountFields,
            ...balanceFields,
            ...insufficientBalanceFields,
            ...paidTypeFields,
            ...periodFields,
          ].filter(Boolean),
        },
      ].filter(Boolean),
      // @ts-ignore
      actions,
    };

    return template;
  }
}
