import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { PrismaService } from '../../prisma/prisma.service';
import { EmailService } from './email.service';
import { EmailType } from '@prisma/client';

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

  constructor(
    private readonly prisma: PrismaService,
    private readonly emailService: EmailService,
  ) {}

  /**
   * Send birthday emails daily at 09:00.
   * Finds clients whose birthDate matches today's month and day.
   */
  @Cron('0 9 * * *')
  async sendBirthdayEmails() {
    this.logger.log('Running birthday email check...');

    const clubs = await this.prisma.club.findMany({
      where: { isActive: true },
      select: { id: true, name: true },
    });

    for (const club of clubs) {
      const moduleEnabled = await this.isEmailEnabled(club.id);
      if (!moduleEnabled) continue;

      const today = new Date();
      const month = today.getMonth() + 1;
      const day = today.getDate();

      const clients = await this.prisma.$queryRaw<
        { id: string; firstName: string; lastName: string; email: string }[]
      >`
        SELECT id, "firstName", "lastName", email
        FROM clients
        WHERE "clubId" = ${club.id}
          AND email IS NOT NULL
          AND EXTRACT(MONTH FROM "birthDate") = ${month}
          AND EXTRACT(DAY FROM "birthDate") = ${day}
      `;

      for (const client of clients) {
        try {
          await this.emailService.send(club.id, {
            recipientEmail: client.email,
            clientId: client.id,
            type: EmailType.BIRTHDAY,
            variables: {
              clientName: `${client.firstName} ${client.lastName}`.trim(),
              clubName: club.name,
            },
          });
        } catch (err: any) {
          this.logger.error(`Birthday email failed for ${client.id}: ${err.message}`);
        }
      }

      if (clients.length > 0) {
        this.logger.log(`Queued ${clients.length} birthday emails for club ${club.name}`);
      }
    }
  }

  /**
   * Send membership expiring emails daily at 10:00.
   * Warns clients whose membership ends within 7 days.
   */
  @Cron('0 10 * * *')
  async sendMembershipExpiringEmails() {
    this.logger.log('Running membership expiring email check...');

    const clubs = await this.prisma.club.findMany({
      where: { isActive: true },
      select: { id: true, name: true },
    });

    for (const club of clubs) {
      const moduleEnabled = await this.isEmailEnabled(club.id);
      if (!moduleEnabled) continue;

      const sevenDaysFromNow = new Date();
      sevenDaysFromNow.setDate(sevenDaysFromNow.getDate() + 7);

      const expiringMemberships = await this.prisma.clientMembership.findMany({
        where: {
          clubId: club.id,
          isActive: true,
          endDate: {
            gte: new Date(),
            lte: sevenDaysFromNow,
          },
        },
        include: {
          client: {
            select: { id: true, firstName: true, lastName: true, email: true },
          },
        },
      });

      for (const membership of expiringMemberships) {
        if (!membership.client.email) continue;

        try {
          await this.emailService.send(club.id, {
            recipientEmail: membership.client.email,
            clientId: membership.client.id,
            type: EmailType.MEMBERSHIP_EXPIRING,
            variables: {
              clientName: `${membership.client.firstName} ${membership.client.lastName}`.trim(),
              clubName: club.name,
              membershipName: membership.name,
              expiryDate: membership.endDate.toLocaleDateString('ru-RU'),
            },
          });
        } catch (err: any) {
          this.logger.error(
            `Membership expiring email failed for ${membership.client.id}: ${err.message}`,
          );
        }
      }

      if (expiringMemberships.length > 0) {
        this.logger.log(
          `Queued ${expiringMemberships.length} membership expiring emails for club ${club.name}`,
        );
      }
    }
  }

  private async isEmailEnabled(clubId: string): Promise<boolean> {
    const mod = await this.prisma.clubModule.findUnique({
      where: { clubId_moduleId: { clubId, moduleId: 'email' } },
    });
    return mod?.enabled ?? false;
  }
}
