import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Cron } from '@nestjs/schedule';
import { DateIvt } from '../date-ivt/entities/date-ivt.entity';
import { QuestionnaireFormData } from '../questionnaire/entities/questionnaire-form-data.entity';
import { MessageService } from './message.service';
import { CronReportService } from '../mailer/cron-report.service';

export interface DateIvtWithQuestionnaire extends Omit<DateIvt, 'generateUuid'> {
  questionnaire?: QuestionnaireFormData;
}

export interface DateIvtGroups {
  inTwoDays: DateIvtWithQuestionnaire[];
  passedOneDay: DateIvtWithQuestionnaire[];
  passedBetweenTwoAndSixDays: DateIvtWithQuestionnaire[];
  passedSevenDays: DateIvtWithQuestionnaire[];
  passedMoreThanSevenDays: DateIvtWithQuestionnaire[];
}

@Injectable()
export class CronService {
  private readonly logger = new Logger(CronService.name);

  constructor(
    @InjectRepository(DateIvt)
    private readonly dateIvtRepository: Repository<DateIvt>,
    @InjectRepository(QuestionnaireFormData)
    private readonly questionnaireRepository: Repository<QuestionnaireFormData>,
    private readonly messageService: MessageService,
    private readonly cronReportService: CronReportService,
  ) {}

  @Cron('0 9 * * *', {
    name: 'processDateIvtRecords',
    timeZone: 'Europe/Paris',
  })
  async processDateIvtRecords(): Promise<void> {
    const startTime = new Date();
    this.logger.log('Starting daily processing of Date IVT records...');

    let groups: DateIvtGroups | null = null;
    let error: Error | null = null;

    try {
      groups = await this.groupDateIvtRecords();

      this.logger.log(
        `Found ${groups.inTwoDays.length} records with IVT date in 2 days`,
      );
      this.logger.log(
        `Found ${groups.passedOneDay.length} records with IVT date passed 1 day ago`,
      );
      this.logger.log(
        `Found ${groups.passedBetweenTwoAndSixDays.length} records with IVT date passed between 2 and 6 days ago`,
      );
      this.logger.log(
        `Found ${groups.passedSevenDays.length} records with IVT date passed 7 days ago`,
      );
      this.logger.log(
        `Found ${groups.passedMoreThanSevenDays.length} records with IVT date passed more than 7 days ago`,
      );

      // Envoyer les messages SMS pour chaque groupe
      const sentMessages = await this.messageService.sendMessagesForAllGroups(groups);

      this.logger.log(
        'Daily processing of Date IVT records completed successfully',
      );

      const endTime = new Date();
      const duration = endTime.getTime() - startTime.getTime();

      // Envoyer le compte-rendu
      await this.cronReportService.sendReport({
        jobName: 'processDateIvtRecords',
        startTime,
        endTime,
        duration,
        status: 'success',
        statistics: {
          inTwoDays: groups.inTwoDays.length,
          passedOneDay: groups.passedOneDay.length,
          passedBetweenTwoAndSixDays:
            groups.passedBetweenTwoAndSixDays.length,
          passedSevenDays: groups.passedSevenDays.length,
          passedMoreThanSevenDays: groups.passedMoreThanSevenDays.length,
          totalRecords: Object.values(groups).reduce(
            (sum, group) => sum + group.length,
            0,
          ),
        },
        details: `Traitement des enregistrements Date IVT terminé. ${Object.values(groups).reduce((sum, group) => sum + group.length, 0)} enregistrements traités au total.`,
        sentMessages,
      });
    } catch (err) {
      error = err instanceof Error ? err : new Error(String(err));
      this.logger.error('Error processing Date IVT records:', error);
      
      const endTime = new Date();
      const duration = endTime.getTime() - startTime.getTime();

      // Envoyer le compte-rendu d'erreur
      await this.cronReportService.sendReport({
        jobName: 'processDateIvtRecords',
        startTime,
        endTime,
        duration,
        status: 'error',
        error: error.message,
      });
    }
  }

  private async groupDateIvtRecords(): Promise<DateIvtGroups> {
    const today = new Date();
    today.setHours(0, 0, 0, 0); // Reset time to start of day

    // Récupérer tous les enregistrements DateIvt
    const allRecords = await this.dateIvtRepository.find();

    // Pour chaque enregistrement, récupérer les données de questionnaire associées
    const recordsWithQuestionnaire: DateIvtWithQuestionnaire[] = [];

    for (const record of allRecords) {
      const questionnaire = await this.questionnaireRepository.findOne({
        where: { id: record.questionnaire_id },
      });

      recordsWithQuestionnaire.push({
        ...record,
        questionnaire: questionnaire || undefined,
      });
    }

    const groups: DateIvtGroups = {
      inTwoDays: [],
      passedOneDay: [],
      passedBetweenTwoAndSixDays: [],
      passedSevenDays: [],
      passedMoreThanSevenDays: [],
    };

    for (const record of recordsWithQuestionnaire) {
      const ivtDate = new Date(record.next_injection_date);
      ivtDate.setHours(0, 0, 0, 0); // Reset time to start of day

      const diffInDays = Math.round(
        (ivtDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24),
      );
      console.log('diffInDays', diffInDays);

      if (diffInDays === 2) {
        // La date d'IVT est dans deux jours à partir d'aujourd'hui (j-2)
        groups.inTwoDays.push(record);
      } else if (diffInDays === -1) {
        // La date d'IVT est passée de 1 jour exactement (j+1)
        groups.passedOneDay.push(record);
      } else if (diffInDays >= -6 && diffInDays <= -2) {
        // La date d'IVT est passée entre 2 et 6 jours (compris)
        groups.passedBetweenTwoAndSixDays.push(record);
      } else if (diffInDays === -7) {
        // La date d'IVT est passée de 7 jours exactement (j+7)
        groups.passedSevenDays.push(record);
      } else if (diffInDays < -7) {
        // La date d'IVT est passée de plus de 7 jours
        // Vérifier s'il n'y a pas d'autre enregistrement pour la même personne avec une date dans le futur
        const hasFutureRecord = recordsWithQuestionnaire.some(
          (otherRecord) =>
            otherRecord.phone_number === record.phone_number &&
            otherRecord.id !== record.id &&
            Math.round(
              (new Date(otherRecord.next_injection_date).getTime() -
                today.getTime()) /
                (1000 * 60 * 60 * 24),
            ) > 0,
        );

        if (!hasFutureRecord) {
          groups.passedMoreThanSevenDays.push(record);
        }
      }
    }

    return groups;
  }

  // Méthode utilitaire pour tester manuellement le groupement
  async testGrouping(): Promise<DateIvtGroups> {
    this.logger.log('Testing Date IVT grouping...');
    return await this.groupDateIvtRecords();
  }

  // Méthode pour tester l'envoi de messages SMS
  async testMessageSending(): Promise<void> {
    this.logger.log('Testing SMS message sending...');

    try {
      const groups = await this.groupDateIvtRecords();
      await this.messageService.sendMessagesForAllGroups(groups);
      this.logger.log('Test SMS sending completed successfully');
    } catch (error) {
      this.logger.error('Error during test SMS sending:', error);
      throw error;
    }
  }
}
