import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as handlebars from 'handlebars';
import { MailService, EmailOptions } from './mail.service';
import { ModelsService } from 'src/models/models.service';

export enum OtpPurpose {
    PHONE_VERIFICATION = 'otp-phone-verification',
    LOGIN = 'otp-login',
}

export interface InviteEmailData {
    inviteUrl?: string;
    inviterName?: string;
    expiryHours?: number;
    password?: string;
    roleLabel?: string;
}

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

    constructor(
        private configService: ConfigService,
        private mailService: MailService,
        private model: ModelsService
    ) { }

    /**
     * Send email using a database template. appName and year are added to `data` automatically;
     * the subject is compiled with the same data.
     */
    async sendEmailFromDBTemplate(
        templateName: string,
        to: string,
        data: any,
        language: string = 'en'
    ): Promise<boolean> {
        try {
            const template = await this.model.EmailTemplateModel.findOne({ name: templateName }).lean();
            if (!template) {
                throw new Error(`Email template '${templateName}' not found in database`);
            }

            const content = template?.[language] || template.en;
            if (!content?.body) {
                throw new Error(`Email template body is empty for language: ${language}`);
            }

            const templateData = {
                appName: this.configService.get<string>('APP_NAME') || 'Ready Broker',
                year: new Date().getFullYear(),
                ...data,
            };

            const emailOptions: EmailOptions = {
                to,
                subject: handlebars.compile(content.subject)(templateData),
                html: handlebars.compile(content.body)(templateData),
            };

            const result = await this.mailService.sendEmail(emailOptions);
            if (result.success) {
                this.logger.log(`Email sent successfully to ${to} using template '${templateName}'`);
                return true;
            }
            return false;
        } catch (error) {
            this.logger.error(`Failed to send email using template '${templateName}' to ${to}`, error.stack);
            throw error;
        }
    }

    /**
     * Send an OTP email for phone verification or login.
     * @param phone - Phone number being verified (used by the phone verification template)
     */
    async sendOTPEmail(
        email: string,
        otp: string,
        purpose: OtpPurpose = OtpPurpose.LOGIN,
        language: string = 'en',
        phone?: string
    ): Promise<boolean> {
        return this.sendEmailFromDBTemplate(purpose, email, { otp, expiryMinutes: 5, phone }, language);
    }

    async sendForgotPasswordEmail(email: string, name: string, resetUrl: string, expiryMinutes: number = 30, language: string = 'en'): Promise<boolean> {
        return this.sendEmailFromDBTemplate(
            'forgot-password',
            email,
            { userName: name || 'User', resetUrl, expiryMinutes },
            language
        );
    }

    async sendBrokerInviteEmail(email: string, name: string, data: InviteEmailData, language: string = 'en'): Promise<boolean> {
        return this.sendEmailFromDBTemplate(
            'invite-broker',
            email,
            { userName: name, inviterName: 'Admin', expiryHours: 48, ...data },
            language
        );
    }

    /** Staff invite: pass `inviteUrl` for a link-based invite and/or `password` to include login credentials. */
    async sendStaffInviteEmail(email: string, name: string, data: InviteEmailData, language: string = 'en'): Promise<boolean> {
        return this.sendEmailFromDBTemplate(
            'invite-staff',
            email,
            { userName: name, email, inviterName: 'Admin', expiryHours: 48, ...data },
            language
        );
    }

    async sendAgentApprovedEmail(email: string, name: string, dashboardUrl: string, language: string = 'en'): Promise<boolean> {
        return this.sendEmailFromDBTemplate('agent-approved', email, { userName: name || 'Agent', dashboardUrl }, language);
    }

    async sendAgentRejectedEmail(email: string, name: string, rejectReason: string, resubmitUrl: string, language: string = 'en'): Promise<boolean> {
        return this.sendEmailFromDBTemplate('agent-rejected', email, { userName: name || 'Agent', rejectReason, resubmitUrl }, language);
    }

    async sendBroadcastEmail(email: string, name: string, subject: string, message: string, language: string = 'en'): Promise<boolean> {
        return this.sendEmailFromDBTemplate(
            'broadcast',
            email,
            { userName: name || 'User', title: subject, message },
            language
        );
    }
}
