const database = require('../config/database');
const { Op } = require('sequelize');
const nodemailer = require('nodemailer');

/**
 * Service-Klasse für Einladungen
 * Verwaltet Einladungs-Emails mit Spam-Schutz
 */
class InviteService {
  constructor() {
    this.emailTransporter = null;
    this.initializeEmailTransporter();
  }

  /**
   * Initialisiert den Email-Transporter
   */
  initializeEmailTransporter() {
    if (!process.env.EMAIL_HOST) {
      console.warn('⚠️  Email-Konfiguration fehlt - Einladungen können nicht versendet werden');
      return;
    }

    this.emailTransporter = nodemailer.createTransport({
      host: process.env.EMAIL_HOST,
      port: parseInt(process.env.EMAIL_PORT) || 587,
      secure: process.env.EMAIL_SECURE === 'true',
      auth: {
        user: process.env.EMAIL_USER,
        pass: process.env.EMAIL_PASSWORD
      }
    });
  }

  /**
   * Sendet eine Einladungs-Email
   * @param {number} inviterUserId - ID des einladenden Users
   * @param {string} inviteeEmail - Email-Adresse des Eingeladenen
   * @returns {Promise<Object>} Einladungs-Info
   */
  async sendInvite(inviterUserId, inviteeEmail) {
    const { User, Invitation } = database.getModels();

    // Validiere Email
    if (!inviteeEmail || !this._isValidEmail(inviteeEmail)) {
      throw new Error('Ungültige Email-Adresse');
    }

    // Hole einladenden User
    const inviter = await User.findByPk(inviterUserId);
    if (!inviter) {
      throw new Error('Benutzer nicht gefunden');
    }

    // Spam-Schutz: Prüfe ob diese Email heute schon eingeladen wurde
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    
    const existingInvite = await Invitation.findOne({
      where: {
        email: inviteeEmail,
        created_at: {
          [Op.gte]: today
        }
      }
    });

    if (existingInvite) {
      throw new Error('Diese Email-Adresse wurde heute bereits eingeladen. Bitte versuchen Sie es morgen erneut.');
    }

    // Prüfe ob Email bereits registriert ist
    const { AuthInfo } = database.getModels();
    const existingUser = await AuthInfo.findOne({
      where: { email: inviteeEmail }
    });

    if (existingUser) {
      throw new Error('Diese Email-Adresse ist bereits registriert');
    }

    // Erstelle Einladungs-Token
    const token = this._generateToken();
    const expiresAt = new Date();
    expiresAt.setDate(expiresAt.getDate() + 7); // 7 Tage gültig

    // Speichere Einladung
    const invitation = await Invitation.create({
      inviter_user_id: inviterUserId,
      email: inviteeEmail,
      token,
      expires_at: expiresAt,
      created_at: new Date(),
      status: 'pending'
    });

    // Sende Email (falls konfiguriert)
    if (this.emailTransporter) {
      await this._sendInviteEmail(inviteeEmail, inviter.full_name, token);
    } else {
      console.warn('⚠️  Email-Transporter nicht konfiguriert - Einladung wurde gespeichert, aber keine Email versendet');
    }

    return {
      id: invitation.id,
      email: inviteeEmail,
      token,
      expiresAt,
      status: 'sent'
    };
  }

  /**
   * Holt alle Einladungen eines Users (optional: nur aktive)
   * @param {number} userId - User-ID
   * @param {boolean} activeOnly - Nur aktive (nicht abgelaufene) Einladungen
   * @returns {Promise<Array>} Array von Einladungen
   */
  async getUserInvitations(userId, activeOnly = false) {
    const { Invitation } = database.getModels();
    
    const where = {
      inviter_user_id: userId
    };

    if (activeOnly) {
      where.expires_at = { [Op.gt]: new Date() };
      where.status = 'pending';
    }

    const invitations = await Invitation.findAll({
      where,
      order: [['created_at', 'DESC']],
      raw: true
    });

    return invitations.map(inv => ({
      id: inv.id,
      email: inv.email,
      createdAt: inv.created_at,
      expiresAt: inv.expires_at,
      status: inv.status,
      isExpired: new Date() > new Date(inv.expires_at)
    }));
  }

  /**
   * Validiert Email-Format
   */
  _isValidEmail(email) {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(email);
  }

  /**
   * Generiert einen zufälligen Token
   */
  _generateToken() {
    return require('crypto').randomBytes(32).toString('hex');
  }

  /**
   * Sendet die Einladungs-Email
   */
  async _sendInviteEmail(toEmail, inviterName, token) {
    const appUrl = process.env.APP_URL || 'http://localhost:5010';
    const registerUrl = `${appUrl}/register?token=${token}`;

    const mailOptions = {
      from: process.env.EMAIL_FROM || process.env.EMAIL_USER,
      to: toEmail,
      subject: 'Einladung zur Stechuhr - Zeiterfassungssystem',
      html: `
        <h2>Einladung zur Stechuhr</h2>
        <p>Hallo,</p>
        <p><strong>${inviterName}</strong> hat Sie eingeladen, die Stechuhr-Zeiterfassung zu nutzen.</p>
        <p>Klicken Sie auf den folgenden Link, um Ihren Account zu erstellen:</p>
        <p><a href="${registerUrl}" style="display: inline-block; padding: 12px 24px; background: #4CAF50; color: white; text-decoration: none; border-radius: 4px;">Account erstellen</a></p>
        <p>Oder kopieren Sie diesen Link in Ihren Browser:</p>
        <p style="word-break: break-all; color: #666;">${registerUrl}</p>
        <p><small>Diese Einladung ist 7 Tage gültig.</small></p>
        <hr>
        <p style="color: #999; font-size: 12px;">
          Wenn Sie diese Einladung nicht erwartet haben, können Sie diese Email ignorieren.
        </p>
      `
    };

    await this.emailTransporter.sendMail(mailOptions);
    console.log(`✉️  Einladungs-Email an ${toEmail} versendet`);
  }
}

module.exports = new InviteService();

