import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import * as nodemailer from 'nodemailer';
import { Subscriber } from './entitity/subscriber.entity';
import { ConfigService } from '@nestjs/config';
import { HostType, SendTo } from 'common/enum/HostType.enum';
import { INewsletterSendOptions } from './interface/Inewsletter.interface';
import { NewsletterLog } from './entitity/newsletter-log.entity';

@Injectable()
export class NewsletterService {
  private transporter: nodemailer.Transporter;

  constructor(
    @InjectRepository(Subscriber)
    private readonly subscriberRepository: Repository<Subscriber>,
    @InjectRepository(NewsletterLog)
    private readonly newsletterLogRepository: Repository<NewsletterLog>,
    private readonly configService: ConfigService,
  ) {
    this.transporter = nodemailer.createTransport({
      host: this.configService.get<string>('NEWSLETTER_SMTP_HOST'),
      port: this.configService.get<number>('NEWSLETTER_SMTP_PORT'),
      secure: true,
      auth: {
        user: this.configService.get<string>('NEWSLETTER_SMTP_USER'),
        pass: this.configService.get<string>('NEWSLETTER_SMTP_PASSWORD'),
      },
      tls: {
        rejectUnauthorized: true,
      },
    });
  }

  async subscribe(email: string, host: HostType): Promise<string> {
    try {
      const existingSubscriber = await this.subscriberRepository.findOne({
        where: { email },
      });

      if (existingSubscriber) {
        if (existingSubscriber.isActive && existingSubscriber.host === host) {
          return `You are already subscribed to ${host} newsletter.`;
        }
        existingSubscriber.isActive = true;
        existingSubscriber.host = host;
        await this.subscriberRepository.save(existingSubscriber);
        return `Successfully re-subscribed to ${host} newsletter.`;
      }

      const newSubscriber = this.subscriberRepository.create({
        email,
        isActive: true,
        host,
      });
      await this.subscriberRepository.save(newSubscriber);
      return `Successfully subscribed to ${host} newsletter.`;
    } catch (error) {
      Logger.error('Error subscribing the user.', error);
      throw new Error('Error subscribing the user.');
    }
  }

  async unsubscribe(email: string, host: HostType): Promise<string> {
    try {
      const existingSubscriber = await this.subscriberRepository.findOne({
        where: { email, host },
      });

      if (!existingSubscriber) {
        return `Email not found in ${host} subscription list.`;
      }

      existingSubscriber.isActive = false;
      await this.subscriberRepository.save(existingSubscriber);
      return `Successfully unsubscribed from ${host} newsletter.`;
    } catch (error) {
      Logger.error('Error unsubscribing the user.', error);
      throw new Error('Error unsubscribing the user.');
    }
  }

  private async getRecipients(sendTo: SendTo, customEmails?: string[]): Promise<string[]> {
    const whereClause: any = { isActive: true };

    switch (sendTo) {
      case SendTo.CAN:
        whereClause.host = HostType.CAN;
        break;
      case SendTo.DFUK:
        whereClause.host = HostType.DFUK;
        break;
      case SendTo.CUSTOM:
        if (!customEmails || customEmails.length === 0) {
          throw new Error('Custom emails array is required when using CUSTOM sendTo option');
        }
        return customEmails;
      case SendTo.ALL:
        break;
    }

    const activeSubscribers = await this.subscriberRepository.find({
      where: whereClause,
    });

    return activeSubscribers.map(subscriber => subscriber.email);
  }

  async sendNewsletter(options: INewsletterSendOptions): Promise<string> {
    try {
      const recipients = await this.getRecipients(options.sendTo, options.customEmails);

      if (recipients.length === 0) {
        return 'No recipients found for the specified criteria.';
      }

      const mailOptions = {
        from: this.configService.get<string>('NEWSLETTER_SMTP_USER'),
        to: recipients.join(', '),
        subject: options.subject,
        html: options.body,
      };

      await this.transporter.sendMail(mailOptions);
      await this.newsletterLogRepository.save({
        host: options.sendTo,
        emailCount: recipients.length,
        subject: options.subject,
        body: options.body,
        sentAt: new Date(),
      });

      return `Newsletter sent successfully to ${recipients.length} recipients!`;
    } catch (error) {
      throw new Error('Error sending the newsletter: ' + error.message);
    }
  }

  async countActiveSubscribers(host: HostType): Promise<number> {
    return this.subscriberRepository.count({
      where: { host, isActive: true },
    });
  }

  async getAllSubscribers(): Promise<Subscriber[]> {
    return this.subscriberRepository.find();
  }

  async getSubscribersByHost(host: HostType): Promise<Subscriber[]> {
    return this.subscriberRepository.find({ where: { host } });
  }

  async getSubscribersByEmail(email: string): Promise<Subscriber[]> {
    return this.subscriberRepository.find({ where: { email } });
  }

  async getSubscribersByStatus(isActive: boolean): Promise<Subscriber[]> {
    return this.subscriberRepository.find({ where: { isActive } });
  }

  async getSubscribersByHostAndStatus(host: HostType, isActive: boolean): Promise<Subscriber[]> {
    return this.subscriberRepository.find({ where: { host, isActive } });
  }

  async countNewslettersSent(host: SendTo): Promise<number> {
    return this.newsletterLogRepository.count({ where: { sendTo: host } });
  }

  async findAllNewsletterLogs(): Promise<NewsletterLog[]> {
    return this.newsletterLogRepository.find();
  }

  async findNewsletterLogById(id: number): Promise<NewsletterLog> {
    return this.newsletterLogRepository.findOne({ where: { id } });
  }

  async deleteNewsletterLog(id: number): Promise<string> {
    await this.newsletterLogRepository.delete({ id });
    return 'Newsletter log deleted successfully.';
  }
}
