// 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>'),
  }));
});

jest.mock('../../../../../utils/logger', () => ({
  info: jest.fn(),
  error: jest.fn(),
  warn: jest.fn(),
}));

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

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

  beforeEach(() => {
    jest.clearAllMocks();
    process.env = {
      ...originalEnv,
      FRONTEND_URL: 'http://localhost:3000',
      SUPPORT_EMAIL: 'support@villageshare.com',
    };
    service = new UserEngagementEmailService();
  });

  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('sendFirstListingCelebrationEmail', () => {
    const owner = { firstName: 'John', email: 'john@example.com' };
    const item = { id: 123, name: 'Power Drill' };

    it('should send first listing celebration email with correct variables', async () => {
      const result = await service.sendFirstListingCelebrationEmail(owner, item);

      expect(result.success).toBe(true);
      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'firstListingCelebrationToOwner',
        expect.objectContaining({
          ownerName: 'John',
          itemName: 'Power Drill',
          itemId: 123,
          viewItemUrl: 'http://localhost:3000/items/123',
        })
      );
      expect(service.emailClient.sendEmail).toHaveBeenCalledWith(
        'john@example.com',
        'Congratulations! Your first item is live on Village Share',
        expect.any(String)
      );
    });

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

      await service.sendFirstListingCelebrationEmail(ownerNoName, item);

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

    it('should handle errors gracefully', async () => {
      service.templateManager.renderTemplate.mockRejectedValueOnce(new Error('Template error'));

      const result = await service.sendFirstListingCelebrationEmail(owner, item);

      expect(result.success).toBe(false);
      expect(result.error).toBe('Template error');
    });
  });

  describe('sendItemDeletionNotificationToOwner', () => {
    const owner = { firstName: 'John', email: 'john@example.com' };
    const item = { id: 123, name: 'Power Drill' };
    const deletionReason = 'Violated community guidelines';

    it('should send item deletion notification with correct variables', async () => {
      const result = await service.sendItemDeletionNotificationToOwner(
        owner,
        item,
        deletionReason
      );

      expect(result.success).toBe(true);
      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'itemDeletionToOwner',
        expect.objectContaining({
          ownerName: 'John',
          itemName: 'Power Drill',
          deletionReason: 'Violated community guidelines',
          supportEmail: 'support@villageshare.com',
          dashboardUrl: 'http://localhost:3000/owning',
        })
      );
      expect(service.emailClient.sendEmail).toHaveBeenCalledWith(
        'john@example.com',
        'Important: Your listing "Power Drill" has been removed',
        expect.any(String)
      );
    });

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

      await service.sendItemDeletionNotificationToOwner(ownerNoName, item, deletionReason);

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

    it('should handle errors gracefully', async () => {
      service.emailClient.sendEmail.mockRejectedValueOnce(new Error('Send error'));

      const result = await service.sendItemDeletionNotificationToOwner(
        owner,
        item,
        deletionReason
      );

      expect(result.success).toBe(false);
      expect(result.error).toBe('Send error');
    });
  });

  describe('sendUserBannedNotification', () => {
    const bannedUser = { firstName: 'John', email: 'john@example.com' };
    const admin = { firstName: 'Admin', lastName: 'User' };
    const banReason = 'Multiple policy violations';

    it('should send user banned notification with correct variables', async () => {
      const result = await service.sendUserBannedNotification(bannedUser, admin, banReason);

      expect(result.success).toBe(true);
      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'userBannedNotification',
        expect.objectContaining({
          userName: 'John',
          banReason: 'Multiple policy violations',
          supportEmail: 'support@villageshare.com',
        })
      );
      expect(service.emailClient.sendEmail).toHaveBeenCalledWith(
        'john@example.com',
        'Important: Your Village Share Account Has Been Suspended',
        expect.any(String)
      );
    });

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

      await service.sendUserBannedNotification(bannedUserNoName, admin, banReason);

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

    it('should handle errors gracefully', async () => {
      service.templateManager.renderTemplate.mockRejectedValueOnce(new Error('Template error'));

      const result = await service.sendUserBannedNotification(bannedUser, admin, banReason);

      expect(result.success).toBe(false);
      expect(result.error).toBe('Template error');
    });
  });
});
