import { Injectable, Logger } from '@nestjs/common';
import { readFileSync } from 'fs';
import { join } from 'path';
import * as Handlebars from 'handlebars';
import { AppConfigService } from '../config/config.service';

/** Ticket #28 — quel template d'email envoyer après validation de compte */
export type ValidationAccountEmailKind = 'parent' | 'am';

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

  /** Cache des templates Handlebars compilés (fichiers .hbs) */
  private readonly compiledTemplates = new Map<ValidationAccountEmailKind, Handlebars.TemplateDelegate>();

  constructor(private readonly configService: AppConfigService) {}

  private templateBasename(kind: ValidationAccountEmailKind): string {
    const map: Record<ValidationAccountEmailKind, string> = {
      parent: 'account-validated-parent',
      am: 'account-validated-am',
    };
    return map[kind];
  }

  private getCompiledTemplate(kind: ValidationAccountEmailKind): Handlebars.TemplateDelegate {
    let compiled = this.compiledTemplates.get(kind);
    if (!compiled) {
      const filePath = join(__dirname, 'templates', `${this.templateBasename(kind)}.hbs`);
      const source = readFileSync(filePath, 'utf8');
      compiled = Handlebars.compile(source);
      this.compiledTemplates.set(kind, compiled);
    }
    return compiled;
  }

  /**
   * Email post-validation : lien création MDP (token existant ou régénéré côté appelant).
   * Ticket #28 — app_name, app_url, expéditeur via ConfigService (sendEmail).
   */
  async sendValidatedAccountPasswordSetupEmail(
    recipient: {
      email: string;
      prenom: string;
      nom: string;
      token: string;
      numeroDossier?: string | null;
    },
    kind: ValidationAccountEmailKind,
  ): Promise<void> {
    const appName = this.configService.get<string>('app_name', "P'titsPas");
    const appUrl = (this.configService.get<string>('app_url', 'https://app.ptits-pas.fr') || '').replace(/\/+$/, '');

    const createPasswordUrl = `${appUrl}/create-password?token=${encodeURIComponent(recipient.token)}`;

    const data: Record<string, string> = {
      prenom: recipient.prenom || '',
      nom: recipient.nom || '',
      appName,
      appUrl,
      createPasswordUrl,
      numeroDossier: recipient.numeroDossier || '',
    };

    const html = this.getCompiledTemplate(kind)(data) as string;

    const subjects: Record<ValidationAccountEmailKind, string> = {
      parent: `${appName} — Compte parent validé : créez votre mot de passe`,
      am: `${appName} — Inscription validée : créez votre mot de passe`,
    };

    await this.sendEmail(recipient.email, subjects[kind], html);
  }

  /**
   * Envoi d'un email générique
   * @param to Destinataire
   * @param subject Sujet
   * @param html Contenu HTML
   * @param text Contenu texte (optionnel)
   */
  async sendEmail(to: string, subject: string, html: string, text?: string): Promise<void> {
    try {
      // Récupération de la configuration SMTP
      const smtpHost = this.configService.get<string>('smtp_host');
      const smtpPort = this.configService.get<number>('smtp_port');
      const smtpSecure = this.configService.get<boolean>('smtp_secure');
      const smtpAuthRequired = this.configService.get<boolean>('smtp_auth_required');
      const smtpUser = this.configService.get<string>('smtp_user');
      const smtpPassword = this.configService.get<string>('smtp_password');
      const emailFromName = this.configService.get<string>('email_from_name');
      const emailFromAddress = this.configService.get<string>('email_from_address');

      // Import dynamique de nodemailer
      const nodemailer = await import('nodemailer');

      // Configuration du transporteur
      const transportConfig: any = {
        host: smtpHost,
        port: smtpPort,
        secure: smtpSecure,
      };

      if (smtpAuthRequired && smtpUser && smtpPassword) {
        transportConfig.auth = {
          user: smtpUser,
          pass: smtpPassword,
        };
      }

      const transporter = nodemailer.createTransport(transportConfig);

      // Envoi de l'email
      await transporter.sendMail({
        from: `"${emailFromName}" <${emailFromAddress}>`,
        to,
        subject,
        text: text || html.replace(/<[^>]*>?/gm, ''), // Fallback texte simple
        html,
      });

      this.logger.log(`📧 Email envoyé à ${to} : ${subject}`);
    } catch (error) {
      this.logger.error(`❌ Erreur lors de l'envoi de l'email à ${to}`, error);
      throw error;
    }
  }

  /**
   * Envoi de l'email de bienvenue pour un gestionnaire
   * @param to Email du gestionnaire
   * @param prenom Prénom
   * @param nom Nom
   * @param token Token de création de mot de passe (si applicable) ou mot de passe temporaire (si applicable)
   * @note Pour l'instant, on suppose que le gestionnaire doit définir son mot de passe via "Mot de passe oublié" ou un lien d'activation
   * Mais le ticket #17 parle de "Flag changement_mdp_obligatoire = TRUE", ce qui implique qu'on lui donne un mot de passe temporaire ou qu'on lui envoie un lien.
   * Le ticket #24 parle de "API Création mot de passe" via token.
   * Pour le ticket #17, on crée le gestionnaire avec un mot de passe (hashé).
   * Si on suit le ticket #35 (Frontend), on saisit un mot de passe.
   * Donc on envoie juste un email de confirmation de création de compte.
   */
  async sendGestionnaireWelcomeEmail(to: string, prenom: string, nom: string): Promise<void> {
    const appName = this.configService.get<string>('app_name', 'P\'titsPas');
    const appUrl = this.configService.get<string>('app_url', 'https://app.ptits-pas.fr');

    const subject = `Bienvenue sur ${appName}`;
    const html = `
      <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
        <h2 style="color: #4CAF50;">Bienvenue ${prenom} ${nom} !</h2>
        <p>Votre compte gestionnaire sur <strong>${appName}</strong> a été créé avec succès.</p>
        <p>Vous pouvez dès à présent vous connecter avec l'adresse email <strong>${to}</strong> et le mot de passe qui vous a été communiqué.</p>
        <p>Lors de votre première connexion, il vous sera demandé de modifier votre mot de passe pour des raisons de sécurité.</p>
        <div style="text-align: center; margin: 30px 0;">
          <a href="${appUrl}" style="background-color: #4CAF50; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px; font-weight: bold;">Accéder à l'application</a>
        </div>
        <hr style="border: 1px solid #eee; margin: 20px 0;">
        <p style="color: #666; font-size: 12px;">
          Cet email a été envoyé automatiquement. Merci de ne pas y répondre.
        </p>
      </div>
    `;

    await this.sendEmail(to, subject, html);
  }

  /**
   * Accusé de réception inscription (parent ou assistante maternelle) :
   * demande enregistrée + n° de dossier. En attente de validation ; pas de lien création MDP à ce stade.
   */
  async sendRegistrationPendingEmail(
    to: string,
    prenom: string,
    nom: string,
    numeroDossier: string,
  ): Promise<void> {
    const appName = this.configService.get<string>('app_name', "P'titsPas");
    const appUrl = this.configService.get<string>('app_url', 'https://app.ptits-pas.fr');

    const safe = (s: string) =>
      (s || '')
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;');

    const subject = `Votre demande d'inscription sur ${appName} — dossier ${safe(numeroDossier)}`;
    const html = `
      <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
        <h2 style="color: #4CAF50;">Bonjour ${safe(prenom)} ${safe(nom)},</h2>
        <p>Nous avons bien enregistré votre demande de création de compte sur <strong>${safe(appName)}</strong>.</p>
        <p><strong>Numéro de dossier :</strong> ${safe(numeroDossier)}</p>
        <p>Votre dossier est <strong>en attente de validation</strong> par notre équipe. Vous recevrez un email lorsqu’il aura été traité.</p>
        <div style="text-align: center; margin: 30px 0;">
          <a href="${appUrl}" style="background-color: #4CAF50; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px; font-weight: bold;">Accéder au site</a>
        </div>
        <hr style="border: 1px solid #eee; margin: 20px 0;">
        <p style="color: #666; font-size: 12px;">Cet email a été envoyé automatiquement. Merci de ne pas y répondre.</p>
      </div>
    `;

    await this.sendEmail(to, subject, html);
  }

  /**
   * Email de refus de dossier avec lien reprise (token).
   * Ticket #110 – Refus sans suppression
   */
  async sendRefusEmail(
    to: string,
    prenom: string,
    nom: string,
    comment: string | undefined,
    token: string,
  ): Promise<void> {
    const appName = this.configService.get<string>('app_name', "P'titsPas");
    const appUrl = this.configService.get<string>('app_url', 'https://app.ptits-pas.fr');
    const repriseLink = `${appUrl}/reprise?token=${encodeURIComponent(token)}`;

    const subject = `Votre dossier – compléments demandés`;
    const commentBlock = comment
      ? `<p><strong>Message du gestionnaire :</strong></p><p>${comment.replace(/</g, '&lt;').replace(/>/g, '&gt;')}</p>`
      : '';
    const html = `
      <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
        <h2 style="color: #333;">Bonjour ${prenom} ${nom},</h2>
        <p>Votre dossier d'inscription sur <strong>${appName}</strong> n'a pas pu être validé en l'état.</p>
        ${commentBlock}
        <p>Vous pouvez corriger les éléments indiqués et soumettre à nouveau votre dossier en cliquant sur le lien ci-dessous.</p>
        <div style="text-align: center; margin: 30px 0;">
          <a href="${repriseLink}" style="background-color: #2196F3; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px; font-weight: bold;">Reprendre mon dossier</a>
        </div>
        <p style="color: #666; font-size: 12px;">Ce lien est valable 7 jours. Si vous n'avez pas demandé cette reprise, vous pouvez ignorer cet email.</p>
        <hr style="border: 1px solid #eee; margin: 20px 0;">
        <p style="color: #666; font-size: 12px;">Cet email a été envoyé automatiquement. Merci de ne pas y répondre.</p>
      </div>
    `;

    await this.sendEmail(to, subject, html);
  }

  /**
   * Ticket #127 — lien application `/reset-password?token=` (pas create-password).
   */
  async sendPasswordResetEmail(recipient: {
    email: string;
    prenom: string;
    nom: string;
    token: string;
  }): Promise<void> {
    const appName = this.configService.get<string>('app_name', "P'titsPas");
    const appUrl = (this.configService.get<string>('app_url', 'https://app.ptits-pas.fr') || '').replace(/\/+$/, '');
    const resetPasswordUrl = `${appUrl}/reset-password?token=${encodeURIComponent(recipient.token)}`;

    const filePath = join(__dirname, 'templates', 'password-reset.hbs');
    const source = readFileSync(filePath, 'utf8');
    const compiled = Handlebars.compile(source);
    const html = compiled({
      prenom: recipient.prenom || '',
      nom: recipient.nom || '',
      appName,
      resetPasswordUrl,
    }) as string;

    const subject = `${appName} — Réinitialisation de votre mot de passe`;
    await this.sendEmail(recipient.email, subject, html);
  }
}
