/* eslint-disable no-await-in-loop */
/* eslint-disable no-restricted-syntax */
import { Inject, Injectable } from '@severo-tech/injection-decorator';
import { ILogger, IDebitNoticeClient, IAgentClient } from '../../contracts';
import { AgentType } from '../../../domain/agent';
import {
  ConciliationOneToOne,
  ConciliationOneToMany,
  ConciliationManyToMany,
} from './handlers';

@Injectable()
export class ConciliateAutomationUseCase {
  @Inject('ZenviaLogger')
  private readonly logger!: ILogger;

  @Inject('ONSDebitNoticeClient')
  private readonly debitNoticeClient!: IDebitNoticeClient;

  @Inject('Agent01EUSTClient')
  private readonly agentClient!: IAgentClient;

  @Inject('ConciliationOneToOne')
  private readonly conciliationOneToOne!: ConciliationOneToOne;

  @Inject('ConciliationOneToMany')
  private readonly conciliationOneToMany!: ConciliationOneToMany;

  @Inject('ConciliationManyToMany')
  private readonly conciliationManyToMany!: ConciliationManyToMany;

  public async execute(year: number, month: number, page = 1): Promise<void> {
    this.logger.info(`"ConciliateInvoicesAutomationUseCase.execute" - Starting to process conciliation for month "${year}/${month}" - Page[${page}]`);

    const startDate = new Date(year, month, -10, 0, 0, 0, 0); // Last month days
    const endDate = new Date(year, month + 1, 0, 23, 59, 59, 999); // Next Month last day

    this.logger.debug(`"ConciliateInvoicesAutomationUseCase.execute" - Searching invoices between "${startDate.toISOString()}" and "${endDate.toISOString()}"`);

    try {
      const debitNotices = await this.debitNoticeClient.getDebitNotice(year, month, page, 20);

      this.logger.debug(`"ConciliateInvoicesAutomationUseCase.execute" - Found ${debitNotices.length} to process - Page[${page}]`);

      for (const debitNotice of debitNotices) {
        const [agent] = await this.agentClient.find({ code: debitNotice.user.code, type: AgentType.User });

        if (agent) {
          await this.conciliationOneToOne.execute(debitNotice.debits, year, month, agent, startDate, endDate);

          await this.conciliationOneToMany.execute(year, month, agent, startDate, endDate);
        }
      }

      this.logger.info(`"ConciliateInvoicesAutomationUseCase.execute" - Finished conciliation for month "${year}/${month}" - Page[${page}]`);

      if (debitNotices.length) { // Go to next page
        await this.execute(year, month, page + 1);
      }

      // Execute ManyToMany Reconciliation only once, after all previous reconciliations have been executed
      if (page === 1) {
        await this.conciliationManyToMany.execute(year, month, startDate, endDate);
      }
    } catch (error) {
      this.logger.error(`"ConciliateInvoicesAutomationUseCase.execute" - Cannot process Conciliation for month "${year}/${month}" - Page[${page}]`, error);
      throw error;
    }
  }
}
