import { EventBus, EventsHandler, IEventHandler } from '@nestjs/cqrs';
import { MidtransCallbackEvent } from 'src/modules/configuration/midtrans/domain/entities/midtrans-callback.event';
import { TransactionDataService } from '../../../data/services/transaction-data.service';
import { TransactionModel } from '../../../data/models/transaction.model';
import {
  BLANK_USER,
  OPERATION,
  STATUS,
} from 'src/core/strings/constants/base.constants';
import { TransactionChangeStatusEvent } from '../../entities/event/transaction-change-status.event';
import * as _ from 'lodash';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { generateInvoiceCodeHelper } from '../managers/helpers/generate-invoice-code.helper';
import { TransactionType } from '../../../constants';
import { WhatsappService } from 'src/services/whatsapp/whatsapp.service';
import * as moment from 'moment';

@EventsHandler(MidtransCallbackEvent)
export class MidtransCallbackHandler
  implements IEventHandler<MidtransCallbackEvent>
{
  constructor(
    private dataService: TransactionDataService,
    private eventBus: EventBus,
  ) {}

  async handle(event: MidtransCallbackEvent) {
    const data_id = event.data.id;
    const data = event.data.data;
    let old_data = undefined;

    const transaction = await this.dataService.getOneByOptions({
      where: {
        id: data_id,
      },
    });
    old_data = _.cloneDeep(transaction);

    if (['capture', 'settlement'].includes(data.transaction_status)) {
      Object.assign(transaction, {
        status: STATUS.SETTLED,
        settlement_date: new Date(data.settlement_time),
        payment_code: await generateInvoiceCodeHelper(this.dataService, 'PMY'),
        payment_code_reference: data.approval_code,
        payment_date: data.settlement_time,
        payment_type_method_name: `Midtrans/${data.payment_type}`,
      });
    } else if (['pending'].includes(data['transaction_status'])) {
      Object.assign(transaction, {
        status: STATUS.PENDING,
      });
    } else {
      Object.assign(transaction, {
        status: STATUS.EXPIRED,
      });
    }

    const queryRunner = this.dataService
      .getRepository()
      .manager.connection.createQueryRunner();

    await this.dataService.create(queryRunner, TransactionModel, transaction);

    if (
      transaction.status === STATUS.SETTLED &&
      transaction.type === TransactionType.ONLINE
    ) {
      const whatsappService = new WhatsappService();
      const formattedDate = moment(transaction.booking_date);
      const payload = {
        id: transaction.id,
        phone: transaction.customer_phone,
        code: transaction.invoice_code,
        name: transaction.customer_name,
        time: formattedDate.valueOf(),
      };
      await whatsappService.bookingCreated(payload);
    }

    if (
      transaction.status === STATUS.EXPIRED &&
      transaction.type === TransactionType.ONLINE
    ) {
      const whatsappService = new WhatsappService();
      const formattedDate = moment(transaction.booking_date);
      const payload = {
        id: transaction.id,
        phone: transaction.customer_phone,
        code: transaction.invoice_code,
        name: transaction.customer_name,
        time: formattedDate.valueOf(),
      };
      await whatsappService.bookingExpired(payload);
    }

    this.eventBus.publish(
      new TransactionChangeStatusEvent({
        id: data_id,
        old: old_data,
        data: {
          ...data,
          status: transaction.status,
          booking_date: transaction.booking_date,
        },
        user: BLANK_USER,
        description: 'Midtrans Callback',
        module: TABLE_NAME.TRANSACTION,
        op: OPERATION.UPDATE,
      }),
    );
  }
}
