import { EventsHandler, IEventHandler } from '@nestjs/cqrs';
import { STATUS } from 'src/core/strings/constants/base.constants';
import { PaymentMethodDataService } from 'src/modules/transaction/payment-method/data/services/payment-method-data.service';
import { TransactionDataService } from 'src/modules/transaction/transaction/data/services/transaction-data.service';
import { TransactionChangeStatusEvent } from 'src/modules/transaction/transaction/domain/entities/event/transaction-change-status.event';
import { sendEmail } from '../helpers/send-email.helper';
import { InvoiceType } from 'src/modules/configuration/export/constants';
import { GeneratePdf } from 'src/modules/configuration/export/domain/templates/helpers/generate-pdf.helper';
import { TransactionUpdatedEvent } from 'src/modules/transaction/transaction/domain/entities/event/transaction-updated.event';
import { RefundChangeStatusEvent } from 'src/modules/transaction/refund/domain/entities/event/refund-change-status.event';
import { RefundCreatedEvent } from 'src/modules/transaction/refund/domain/entities/event/refund-created.event';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { Logger } from '@nestjs/common';

@EventsHandler(
  TransactionChangeStatusEvent,
  TransactionUpdatedEvent,
  RefundChangeStatusEvent,
  RefundCreatedEvent,
)
export class PaymentTransactionHandler
  implements IEventHandler<TransactionChangeStatusEvent>
{
  constructor(
    private dataService: TransactionDataService,
    private paymentService: PaymentMethodDataService,
  ) {}

  async handle(event: TransactionChangeStatusEvent) {
    try {
      const old_data = event.data.old;
      const current_data = event.data.data;
      const data_id = current_data.transaction_id ?? event.data.id;
      const from_refund = event.data.module == TABLE_NAME.REFUND;

      const payments = await this.paymentService.getManyByOptions({
        where: {
          status: STATUS.ACTIVE,
        },
      });

      let transaction = await this.dataService.getOneByOptions({
        where: {
          id: data_id,
        },
        relations: [
          'items',
          'refunds',
          'refunds.refund_items',
          'refunds.refund_items.transaction_item',
        ],
      });

      if (!transaction) {
        transaction = await this.dataService.getOneByOptions({
          where: {
            id: event.data.id,
          },
          relations: [
            'items',
            'refunds',
            'refunds.refund_items',
            'refunds.refund_items.transaction_item',
          ],
        });
      }

      Object.assign(transaction, {
        booking_date: new Date(transaction.booking_date).toDateString(),
        booking_date_before: new Date(
          transaction.booking_date_before,
        ).toDateString(),
        email: transaction.customer_email,
        payment_methods: payments,
      });

      const refund = transaction?.['refunds']?.find(
        (refund) => ![STATUS.CANCEL].includes(refund.status),
      );
      if (refund) {
        Object.assign(refund, {
          refund_date: new Date(refund?.refund_date).toDateString(),
          request_date: new Date(refund?.request_date).toDateString(),
          refund_total: Number(refund?.refund_total).toLocaleString('id-ID', {
            style: 'currency',
            currency: 'IDR',
          }),
        });

        Object.assign(transaction, {
          refund: refund,
        });
      }

      if (transaction?.['refund']?.refund_items.length > 0) {
        Object.assign(transaction, {
          refund_items: `
          <p>Refund Items:</p>
          <ul style="padding-left:15px">
            ${transaction?.['refund']?.refund_items
              ?.filter((item) => Number(item.qty_refund) > 0)
              .map((item) => {
                return `
                <li>${item.qty_refund} ${item.transaction_item.item_name} </li>
              `;
              })}
            </ul>`,

          refund_items_data: transaction?.['refund']?.refund_items
            ?.filter((item) => Number(item.qty_refund) > 0)
            .map((item) => {
              return {
                qty_refund: item.qty_refund,
                item_name: item.transaction_item.item_name,
              };
            }),
        });
      }

      if (!transaction.customer_email) return;

      // refund request
      if (
        from_refund &&
        transaction['refund'] &&
        [STATUS.DRAFT].includes(transaction['refund'].status)
      ) {
        Logger.verbose('Send Refund Request', 'PaymentTransaction');
        const pdf = await GeneratePdf(
          transaction,
          InvoiceType.REFUND_REQUEST,
          payments,
        );
        sendEmail(
          [
            {
              ...transaction,
              payment_total: Number(transaction.payment_total).toLocaleString(
                'id-ID',
                {
                  style: 'currency',
                  currency: 'IDR',
                },
              ),
            },
          ],
          InvoiceType.REFUND_REQUEST,
          pdf,
        );
      }

      // refund confirmation
      else if (
        from_refund &&
        transaction['refund'] &&
        transaction['refund'].status == STATUS.REFUNDED
      ) {
        Logger.verbose('Send Refund Confirmation', 'PaymentTransaction');
        const pdf = await GeneratePdf(
          transaction,
          InvoiceType.REFUND_CONFIRMATION,
          payments,
        );
        sendEmail(
          [
            {
              ...transaction,
              payment_total: Number(transaction.payment_total).toLocaleString(
                'id-ID',
                {
                  style: 'currency',
                  currency: 'IDR',
                },
              ),
            },
          ],
          InvoiceType.REFUND_CONFIRMATION,
          pdf,
        );
      }

      // payment settled
      else if (
        !from_refund &&
        old_data.status != current_data.status &&
        [STATUS.ACTIVE, STATUS.SETTLED].includes(current_data.status)
      ) {
        Logger.verbose('Send Payment Settled', 'PaymentTransaction');
        const pdf = await GeneratePdf(
          transaction,
          InvoiceType.PAYMENT_CONFIRMATION,
          payments,
        );
        sendEmail(
          [
            {
              ...transaction,
              payment_total: Number(transaction.payment_total).toLocaleString(
                'id-ID',
                {
                  style: 'currency',
                  currency: 'IDR',
                },
              ),
            },
          ],
          InvoiceType.PAYMENT_CONFIRMATION,
          pdf,
        );
      }

      // payment confirm to pending
      else if (
        !from_refund &&
        old_data.status != current_data.status &&
        [STATUS.PENDING].includes(current_data.status)
      ) {
        Logger.verbose('Send Confirmation to Pending', 'PaymentTransaction');
        const pdf = await GeneratePdf(
          transaction,
          InvoiceType.BOOKING_INVOICE,
          payments,
        );
        sendEmail(
          [
            {
              ...transaction,
              payment_total: Number(transaction.payment_total).toLocaleString(
                'id-ID',
                {
                  style: 'currency',
                  currency: 'IDR',
                },
              ),
            },
          ],
          InvoiceType.BOOKING_INVOICE,
          pdf,
        );
      }
      // payment expired
      else if (
        !from_refund &&
        old_data.status != current_data.status &&
        [STATUS.PENDING, STATUS.EXPIRED].includes(current_data.status)
      ) {
        Logger.verbose('Send Payment Expired', 'PaymentTransaction');
        const pdf = await GeneratePdf(
          transaction,
          InvoiceType.INVOICE_EXPIRED,
          payments,
        );
        sendEmail(
          [
            {
              ...transaction,
              payment_total: Number(transaction.payment_total).toLocaleString(
                'id-ID',
                {
                  style: 'currency',
                  currency: 'IDR',
                },
              ),
            },
          ],
          InvoiceType.INVOICE_EXPIRED,
          pdf,
        );
      }

      // change booking date
      else if (
        !from_refund &&
        old_data.booking_date != current_data.booking_date &&
        [STATUS.SETTLED, STATUS.ACTIVE, STATUS.PENDING].includes(
          current_data.status,
        )
      ) {
        Logger.verbose('Send Change Booking Date', 'PaymentTransaction');
        const pdf = await GeneratePdf(
          transaction,
          InvoiceType.BOOKING_DATE_CHANGE,
          payments,
        );
        sendEmail(
          [
            {
              ...transaction,
              payment_total: Number(transaction.payment_total).toLocaleString(
                'id-ID',
                {
                  style: 'currency',
                  currency: 'IDR',
                },
              ),
            },
          ],
          InvoiceType.BOOKING_DATE_CHANGE,
          pdf,
        );
      }
    } catch (error) {
      console.log(error);
    }
  }
}
