// Mock dependencies
jest.mock('../../../../../services/email/core/EmailClient', () => {
  return jest.fn().mockImplementation(() => ({
    initialize: jest.fn().mockResolvedValue(),
    sendEmail: jest.fn().mockResolvedValue({ success: true, messageId: 'msg-123' }),
  }));
});

jest.mock('../../../../../services/email/core/TemplateManager', () => {
  return jest.fn().mockImplementation(() => ({
    initialize: jest.fn().mockResolvedValue(),
    renderTemplate: jest.fn().mockResolvedValue('<html>Test</html>'),
  }));
});

const AuthEmailService = require('../../../../../services/email/domain/AuthEmailService');

describe('AuthEmailService', () => {
  let service;
  const originalEnv = process.env;

  beforeEach(() => {
    jest.clearAllMocks();
    process.env = { ...originalEnv, FRONTEND_URL: 'http://localhost:3000' };
    service = new AuthEmailService();
  });

  afterEach(() => {
    process.env = originalEnv;
  });

  describe('initialize', () => {
    it('should initialize only once', async () => {
      await service.initialize();
      await service.initialize();

      expect(service.emailClient.initialize).toHaveBeenCalledTimes(1);
      expect(service.templateManager.initialize).toHaveBeenCalledTimes(1);
    });
  });

  describe('sendVerificationEmail', () => {
    it('should send verification email with correct variables', async () => {
      const user = { firstName: 'John', email: 'john@example.com' };
      const token = 'verify-token';

      const result = await service.sendVerificationEmail(user, token);

      expect(result.success).toBe(true);
      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'emailVerificationToUser',
        expect.objectContaining({
          recipientName: 'John',
          verificationUrl: 'http://localhost:3000/verify-email?token=verify-token',
        })
      );
      expect(service.emailClient.sendEmail).toHaveBeenCalledWith(
        'john@example.com',
        'Verify Your Email - Village Share',
        expect.any(String)
      );
    });

    it('should use default name when firstName is missing', async () => {
      const user = { email: 'john@example.com' };
      const token = 'verify-token';

      await service.sendVerificationEmail(user, token);

      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'emailVerificationToUser',
        expect.objectContaining({ recipientName: 'there' })
      );
    });
  });

  describe('sendPasswordResetEmail', () => {
    it('should send password reset email with reset URL', async () => {
      const user = { firstName: 'Jane', email: 'jane@example.com' };
      const token = 'reset-token';

      const result = await service.sendPasswordResetEmail(user, token);

      expect(result.success).toBe(true);
      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'passwordResetToUser',
        expect.objectContaining({
          recipientName: 'Jane',
          resetUrl: 'http://localhost:3000/reset-password?token=reset-token',
        })
      );
    });
  });

  describe('sendPasswordChangedEmail', () => {
    it('should send password changed confirmation', async () => {
      const user = { firstName: 'John', email: 'john@example.com' };

      const result = await service.sendPasswordChangedEmail(user);

      expect(result.success).toBe(true);
      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'passwordChangedToUser',
        expect.objectContaining({
          recipientName: 'John',
          email: 'john@example.com',
          timestamp: expect.any(String),
        })
      );
    });
  });

  describe('sendPersonalInfoChangedEmail', () => {
    it('should send personal info changed notification', async () => {
      const user = { firstName: 'John', email: 'john@example.com' };

      const result = await service.sendPersonalInfoChangedEmail(user);

      expect(result.success).toBe(true);
      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'personalInfoChangedToUser',
        expect.objectContaining({ recipientName: 'John' })
      );
    });
  });

  describe('sendTwoFactorOtpEmail', () => {
    it('should send OTP code email', async () => {
      const user = { firstName: 'John', email: 'john@example.com' };
      const otpCode = '123456';

      const result = await service.sendTwoFactorOtpEmail(user, otpCode);

      expect(result.success).toBe(true);
      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'twoFactorOtpToUser',
        expect.objectContaining({
          recipientName: 'John',
          otpCode: '123456',
        })
      );
    });
  });

  describe('sendTwoFactorEnabledEmail', () => {
    it('should send 2FA enabled confirmation', async () => {
      const user = { firstName: 'John', email: 'john@example.com' };

      const result = await service.sendTwoFactorEnabledEmail(user);

      expect(result.success).toBe(true);
      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'twoFactorEnabledToUser',
        expect.objectContaining({ recipientName: 'John' })
      );
    });
  });

  describe('sendTwoFactorDisabledEmail', () => {
    it('should send 2FA disabled notification', async () => {
      const user = { firstName: 'John', email: 'john@example.com' };

      const result = await service.sendTwoFactorDisabledEmail(user);

      expect(result.success).toBe(true);
      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'twoFactorDisabledToUser',
        expect.objectContaining({ recipientName: 'John' })
      );
    });
  });

  describe('sendRecoveryCodeUsedEmail', () => {
    it('should send recovery code used notification with green color for many codes', async () => {
      const user = { firstName: 'John', email: 'john@example.com' };

      const result = await service.sendRecoveryCodeUsedEmail(user, 8);

      expect(result.success).toBe(true);
      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'recoveryCodeUsedToUser',
        expect.objectContaining({
          remainingCodes: 8,
          remainingCodesColor: '#28a745',
          lowCodesWarning: false,
        })
      );
    });

    it('should use orange color for medium remaining codes', async () => {
      const user = { firstName: 'John', email: 'john@example.com' };

      await service.sendRecoveryCodeUsedEmail(user, 4);

      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'recoveryCodeUsedToUser',
        expect.objectContaining({
          remainingCodesColor: '#fd7e14',
        })
      );
    });

    it('should use red color and warning for low remaining codes', async () => {
      const user = { firstName: 'John', email: 'john@example.com' };

      await service.sendRecoveryCodeUsedEmail(user, 1);

      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'recoveryCodeUsedToUser',
        expect.objectContaining({
          remainingCodesColor: '#dc3545',
          lowCodesWarning: true,
        })
      );
    });
  });
});
