/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { DEVOLUCIONResumen, Notify, UserData } from '@common/cron.interface';
import { NotificationsService } from '@modules/notifications/notifications.service';
import { ShoppingsService } from '@modules/shoppings/shoppings.service';
import { UsersService } from '@modules/users/users.service';
import { Injectable, Logger } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';

@Injectable()
export class CronService {
  private readonly logger = new Logger('cron tasks');
  private tokens: string[] = [];

  constructor(
    private readonly shoppingService: ShoppingsService,
    private readonly notifyService: NotificationsService,
    private readonly userService: UsersService,
  ) {}

  @Cron('0 0 8 * * *', {
    timeZone: 'America/Mexico_City',
  })
  async handleCron() {
    this.tokens = [];
    const shops: DEVOLUCIONResumen[] =
      await this.shoppingService.getWeekDevoluciones();

    for (const b of shops) {
      b.fecha.setUTCHours(0, 0, 0, 0);
      const dias = this.daysUntil(b.fecha);

      if (dias === 2 && !b.caducado) {
        await this.enviarAviso(b, 2);
      } else if (dias === 1 && !b.caducado) {
        await this.enviarAviso(b, 1);
      } else if (dias === 0 && !b.caducado) {
        await this.enviarAviso(b, 0);
      }
    }

    const notify: Notify = {
      title: 'Tienes devoluciones próximas',
      body: `Entra a CtrlClick para consultar notificaciones.`,
      data: {
        type: 'info',
      },
    };

    for (const token of this.tokens) {
      await this.notifyService.createCronNotificationPush(notify, token);
    }
  }

  private daysUntil(date: Date): number {
    const hoy = new Date();
    hoy.setUTCHours(0, 0, 0, 0);
    const target = new Date(date);
    target.setUTCHours(0, 0, 0, 0);

    const diffMs = target.getTime() - hoy.getTime();
    return Math.floor(diffMs / (1000 * 60 * 60 * 24));
  }

  private async enviarAviso(boleto: DEVOLUCIONResumen, dia: number) {
    if (boleto.diferencia > 0) {
      await this.findBusinessAdmins(boleto, dia);
    }
  }

  private async findBusinessAdmins(boleto: DEVOLUCIONResumen, dia: number) {
    const admins: UserData[] = await this.userService.findAllForCron(
      boleto.businessId,
    );

    let notify!: Notify;
    const soloFecha = new Date(boleto.fecha).toISOString().split('T')[0];

    switch (dia) {
      case 2:
        notify = {
          title: 'Devolución dentro 2 días',
          body: `Producto ${boleto.identificador}, devoluciones: ${boleto.diferencia}; sorteo ${boleto.sorteo}, fecha: ${soloFecha}`,
          data: {
            type: 'warning',
          },
        };
        break;
      case 1:
        notify = {
          title: 'Devolución dentro 1 día',
          body: `Producto ${boleto.identificador}, devoluciones: ${boleto.diferencia}; sorteo ${boleto.sorteo}, fecha: ${soloFecha}`,
          data: {
            type: 'warning',
          },
        };
        break;
      default:
        notify = {
          title: 'Devolución hoy',
          body: `Producto ${boleto.identificador}, devoluciones: ${boleto.diferencia}; sorteo ${boleto.sorteo}, fecha: ${soloFecha}`,
          data: {
            type: 'danger',
          },
        };
    }

    for (const user of admins) {
      const exists = this.tokens.indexOf(user.token!);
      if (exists < 0) {
        this.tokens.push(user.token!);
      }

      await this.notifyService.createCronNotification({
        ...notify,
        userId: user._id,
      });
    }
  }
}
