import prettyMsI18n from 'pretty-ms-i18n';
import { formatTokenAmount, getOwnerDid } from '../../util';
import { translate } from '../../../locales';
import { Invoice, PaymentCurrency, Subscription } from '../../../store/models';
import type { BaseEmailTemplate, BaseEmailTemplateType } from './base';
import { getUserLocale } from '../../../integrations/blocklet/notification';
import { formatTime, getPrettyMsI18nLocale } from '../../time';
import { getAdminSubscriptionPageUrl, getAdminInvoicePageUrl } from '../../subscription';
import { getMainProductName } from '../../product';
import { getInvoiceShouldPayTotal } from '../../invoice';

export interface BillingDiscrepancyEmailTemplateOptions {
  invoiceId: string;
}

interface BillingDiscrepancyEmailTemplateContext {
  locale: string;
  userDid: string;
  productName: string;
  subscriptionId: string;
  billingAmount: string;
  shouldPayAmount: string;
  invoiceId: string;
  currentPeriodStart: string;
  currentPeriodEnd: string;
  duration: string;
  viewSubscriptionLink: string;
  viewInvoiceLink: string;
}

export class BillingDiscrepancyEmailTemplate implements BaseEmailTemplate<BillingDiscrepancyEmailTemplateContext> {
  options: BillingDiscrepancyEmailTemplateOptions;

  constructor(options: BillingDiscrepancyEmailTemplateOptions) {
    this.options = options;
  }

  async getContext(): Promise<BillingDiscrepancyEmailTemplateContext> {
    const { invoiceId } = this.options;
    const invoice = await Invoice.findByPk(invoiceId);
    if (!invoice) {
      throw new Error(`Invoice not found: ${invoiceId}`);
    }
    const subscriptionId = invoice.subscription_id;
    const subscription: Subscription | null = await Subscription.findByPk(subscriptionId);
    if (!subscription) {
      throw new Error(`Subscription not found: ${subscriptionId}`);
    }
    const paymentCurrency = (await PaymentCurrency.findOne({
      where: {
        id: subscription.currency_id,
      },
    })) as PaymentCurrency;

    const userDid = await getOwnerDid();
    if (!userDid) {
      throw new Error('get owner did failed');
    }
    const locale = await getUserLocale(userDid);
    const productName = await getMainProductName(subscription.id);
    const currentPeriodStart = formatTime(invoice.period_start * 1000);
    const currentPeriodEnd = formatTime(invoice.period_end * 1000);
    const duration: string = prettyMsI18n(
      new Date(currentPeriodEnd).getTime() - new Date(currentPeriodStart).getTime(),
      {
        locale: getPrettyMsI18nLocale(locale),
      }
    );
    const viewSubscriptionLink = getAdminSubscriptionPageUrl({
      subscriptionId: subscription.id,
      locale,
      userDid,
    });
    const viewInvoiceLink = getAdminInvoicePageUrl({
      invoiceId,
      userDid,
      locale,
    });

    const billingAmount = `${formatTokenAmount(invoice.total, paymentCurrency.decimal)} ${paymentCurrency.symbol}`;

    const shouldPayTotal = await getInvoiceShouldPayTotal(invoice);
    if (shouldPayTotal === invoice.total) {
      throw new Error('should pay total is equal to invoice total, no need to send billing discrepancy notification');
    }
    const shouldPayAmount = `${formatTokenAmount(shouldPayTotal, paymentCurrency.decimal)} ${paymentCurrency.symbol}`;
    return {
      userDid,
      locale,
      productName,
      subscriptionId: subscription.id,
      billingAmount,
      shouldPayAmount,
      invoiceId,
      currentPeriodStart,
      currentPeriodEnd,
      duration,
      viewSubscriptionLink,
      viewInvoiceLink,
    };
  }

  async getTemplate(): Promise<BaseEmailTemplateType> {
    const {
      locale,
      productName,
      subscriptionId,
      billingAmount,
      currentPeriodStart,
      currentPeriodEnd,
      duration,
      viewSubscriptionLink,
      viewInvoiceLink,
      shouldPayAmount,
    } = await this.getContext();

    const template: BaseEmailTemplateType = {
      title: translate('notification.billingDiscrepancy.title', locale, {
        productName,
      }),
      body: translate('notification.billingDiscrepancy.body', locale, {
        productName,
      }),
      attachments: [
        {
          type: 'section',
          fields: [
            {
              type: 'text',
              data: {
                type: 'plain',
                color: '#9397A1',
                text: translate('notification.common.product', locale),
              },
            },
            {
              type: 'text',
              data: {
                type: 'plain',
                text: productName,
              },
            },
            {
              type: 'text',
              data: {
                type: 'plain',
                color: '#9397A1',
                text: translate('notification.common.subscriptionId', locale),
              },
            },
            {
              type: 'text',
              data: {
                type: 'plain',
                text: subscriptionId,
              },
            },
            {
              type: 'text',
              data: {
                type: 'plain',
                color: '#9397A1',
                text: translate('notification.common.shouldPayAmount', locale),
              },
            },
            {
              type: 'text',
              data: {
                type: 'plain',
                text: shouldPayAmount,
              },
            },
            {
              type: 'text',
              data: {
                type: 'plain',
                color: '#9397A1',
                text: translate('notification.common.billedAmount', locale),
              },
            },
            {
              type: 'text',
              data: {
                type: 'plain',
                text: billingAmount,
              },
            },
            {
              type: 'text',
              data: {
                type: 'plain',
                color: '#9397A1',
                text: translate('notification.common.validityPeriod', locale),
              },
            },
            {
              type: 'text',
              data: {
                type: 'plain',
                text: `${currentPeriodStart} ~ ${currentPeriodEnd}(${duration})`,
              },
            },
          ].filter(Boolean),
        },
      ],
      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,
        },
      ].filter(Boolean),
    };

    return template;
  }
}
