/* eslint-disable @typescript-eslint/brace-style */
/* eslint-disable @typescript-eslint/indent */
import camelCase from 'lodash/camelCase';

import { getUserLocale } from '../../../integrations/blocklet/notification';
import { translate } from '../../../locales';
import { AutoRechargeConfig, Customer, Invoice, PaymentMethod, Price, Product } from '../../../store/models';
import { PaymentCurrency } from '../../../store/models/payment-currency';
import { getCustomerInvoicePageUrl } from '../../invoice';
import { SufficientForPaymentResult, getPaymentDetail } from '../../payment';
import { formatTime } from '../../time';
import { formatCurrencyInfo, getCustomerAutoRechargeSettingsUrl } from '../../util';
import type { BaseEmailTemplate, BaseEmailTemplateType } from './base';

// Extended result type that includes skipped reasons
export interface AutoRechargeResult extends Partial<SufficientForPaymentResult> {
  sufficient?: boolean;
  reason?: string;
  // Skipped scenario fields
  currentRate?: string;
  minAcceptableRate?: string;
  // Additional context for better notifications
  paymentCurrencySymbol?: string;
  paymentCurrencyName?: string;
  creditCurrencyName?: string;
}

export interface CustomerAutoRechargeFailedEmailTemplateOptions {
  customerId: string;
  autoRechargeConfigId: string;
  invoiceId?: string; // Optional for skipped scenarios
  paymentIntentId?: string; // Optional for skipped scenarios
  result: AutoRechargeResult;
}

interface CustomerAutoRechargeFailedEmailTemplateContext {
  locale: string;
  userDid: string;
  at: string;
  reason: string;
  paymentInfo?: string;
  autoRechargeAmount?: string;
  creditCurrencyName: string;
  viewInvoiceLink?: string;
  settingsUrl?: string;
  isSkipped: boolean;
}

export class CustomerAutoRechargeFailedEmailTemplate implements BaseEmailTemplate<CustomerAutoRechargeFailedEmailTemplateContext> {
  options: CustomerAutoRechargeFailedEmailTemplateOptions;

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

  private isSkippedScenario(): boolean {
    const skippedReasons = ['slippage_exceeded', 'exchange_rate_not_supported', 'exchange_rate_fetch_failed'];
    return skippedReasons.includes(this.options.result?.reason || '');
  }

  // Get the title key based on the skip reason
  private getSkippedTitleKey(): string {
    const reason = this.options.result?.reason;
    const titleMap: Record<string, string> = {
      slippage_exceeded: 'titleSkippedSlippageExceeded',
      exchange_rate_not_supported: 'titleSkippedExchangeRateNotSupported',
      exchange_rate_fetch_failed: 'titleSkippedExchangeRateFetchFailed',
    };
    return `notification.autoRechargeFailed.${titleMap[reason || ''] || 'titleSkipped'}`;
  }

  private getSkippedReason(locale: string): string {
    const { result } = this.options;
    const i18nText = `notification.autoRechargeFailed.reason.${camelCase(result.reason as string)}`;

    return translate(i18nText, locale, {
      currentRate: result.currentRate || '-',
      minAcceptableRate: result.minAcceptableRate || '-',
      paymentCurrency: result.paymentCurrencySymbol || result.paymentCurrencyName || '-',
    });
  }

  private async getFailedReason(userDid: string, invoice: Invoice, locale: string): Promise<string> {
    if (this.options.result?.sufficient) {
      throw new Error(`SufficientForPaymentResult.sufficient should be false: ${JSON.stringify(this.options.result)}`);
    }

    const i18nText = `notification.autoRechargeFailed.reason.${camelCase(this.options.result.reason as string)}`;

    const paymentDetail = await getPaymentDetail(userDid, invoice);
    const reason = translate(i18nText, locale, {
      balance: `${paymentDetail.balance} ${paymentDetail.symbol}`,
      price: `${paymentDetail.price} ${paymentDetail.symbol}`,
    });

    return reason;
  }

  async getContext(): Promise<CustomerAutoRechargeFailedEmailTemplateContext> {
    const customer = await Customer.findByPk(this.options.customerId);
    if (!customer) {
      throw new Error(`Customer not found: ${this.options.customerId}`);
    }

    const autoRechargeConfig = await AutoRechargeConfig.findByPk(this.options.autoRechargeConfigId, {
      include: [
        {
          model: Price,
          as: 'price',
          include: [{ model: Product, as: 'product' }],
        },
      ],
    });
    if (!autoRechargeConfig) {
      throw new Error(`AutoRechargeConfig not found: ${this.options.autoRechargeConfigId}`);
    }

    const userDid: string = customer.did;
    const locale = await getUserLocale(userDid);
    const at: string = formatTime(Date.now());
    const isSkipped = this.isSkippedScenario();

    // Get credit currency
    const creditCurrency = await PaymentCurrency.findByPk(autoRechargeConfig.currency_id);
    if (!creditCurrency) {
      throw new Error(`Credit currency not found: ${autoRechargeConfig.currency_id}`);
    }
    const creditCurrencyName = creditCurrency.name || 'Credits';

    // Handle skipped scenario (no invoice)
    if (isSkipped) {
      const reason = this.getSkippedReason(locale);
      const settingsUrl = getCustomerAutoRechargeSettingsUrl({
        locale,
        userDid,
        currencyId: autoRechargeConfig.currency_id,
      });
      return {
        locale,
        userDid,
        at,
        reason,
        creditCurrencyName,
        settingsUrl,
        isSkipped: true,
      };
    }

    // Handle normal failed scenario (with invoice)
    const invoice = await Invoice.findByPk(this.options.invoiceId);
    if (!invoice) {
      throw new Error(`Invoice not found: ${this.options.invoiceId}`);
    }

    const paymentCurrency = (await PaymentCurrency.findOne({
      where: {
        id: invoice.currency_id,
      },
    })) as PaymentCurrency;

    const reason: string = await this.getFailedReason(userDid, invoice, locale);

    const paymentMethod: PaymentMethod | null = await PaymentMethod.findByPk(invoice.default_payment_method_id);
    const paymentInfo: string = formatCurrencyInfo(invoice.amount_remaining, paymentCurrency, paymentMethod);

    // Format auto recharge amount (based on invoice amount)
    const autoRechargeAmount = formatCurrencyInfo(invoice.amount_remaining, paymentCurrency, paymentMethod);

    const viewInvoiceLink = getCustomerInvoicePageUrl({
      invoiceId: invoice.id,
      userDid,
      locale,
      action: 'pay',
    });

    return {
      locale,
      userDid,
      at,
      reason,
      paymentInfo,
      autoRechargeAmount,
      creditCurrencyName,
      viewInvoiceLink,
      isSkipped: false,
    };
  }

  async getTemplate(): Promise<BaseEmailTemplateType> {
    const context = await this.getContext();
    const { locale, userDid, at, reason, paymentInfo, creditCurrencyName, viewInvoiceLink, settingsUrl, isSkipped } =
      context;

    // Use different title/body for skipped scenarios
    // For skipped scenarios, use reason-specific title
    const titleKey = isSkipped ? this.getSkippedTitleKey() : 'notification.autoRechargeFailed.title';
    const bodyKey = isSkipped ? 'notification.autoRechargeFailed.bodySkipped' : 'notification.autoRechargeFailed.body';

    const fields = [
      {
        type: 'text',
        data: {
          type: 'plain',
          color: '#9397A1',
          text: translate('notification.common.account', locale),
        },
      },
      {
        type: 'text',
        data: {
          type: 'plain',
          text: userDid,
        },
      },
    ];

    // Add payment amount field only for non-skipped scenarios
    if (!isSkipped && paymentInfo) {
      fields.push(
        {
          type: 'text',
          data: {
            type: 'plain',
            color: '#9397A1',
            text: translate('notification.common.paymentAmount', locale),
          },
        },
        {
          type: 'text',
          data: {
            type: 'plain',
            text: paymentInfo,
          },
        }
      );
    }

    // Add reason field
    fields.push(
      {
        type: 'text',
        data: {
          type: 'plain',
          color: '#9397A1',
          text: translate('notification.common.failReason', locale),
        },
      },
      {
        type: 'text',
        data: {
          type: 'plain',
          color: isSkipped ? '#FF9500' : '#FF0000', // Orange for skipped, red for failed
          text: reason,
        },
      }
    );

    // Build actions based on scenario
    const actions = [];
    if (isSkipped && settingsUrl) {
      // For skipped scenarios, link to settings to adjust slippage config
      actions.push({
        name: translate('notification.autoRechargeFailed.adjustSettings', locale),
        title: translate('notification.autoRechargeFailed.adjustSettings', locale),
        link: settingsUrl,
      });
    } else if (viewInvoiceLink) {
      // For failed scenarios, link to invoice to retry payment
      actions.push({
        name: translate('notification.common.renewNow', locale),
        title: translate('notification.common.renewNow', locale),
        link: viewInvoiceLink,
      });
    }

    const template: BaseEmailTemplateType = {
      title: translate(titleKey, locale),
      body: translate(bodyKey, locale, {
        at,
        creditCurrencyName,
      }),
      // @ts-expect-error
      attachments: [
        {
          type: 'section',
          fields: fields.filter(Boolean),
        },
      ].filter(Boolean),
      // @ts-ignore
      actions,
    };

    return template;
  }
}
