// 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 CustomerServiceEmailService = require('../../../../../services/email/domain/CustomerServiceEmailService');

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

  beforeEach(() => {
    jest.clearAllMocks();
    process.env = {
      ...originalEnv,
      CUSTOMER_SUPPORT_EMAIL: 'support@example.com',
    };
    service = new CustomerServiceEmailService();
  });

  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('sendLateReturnToCustomerService', () => {
    const rental = {
      id: 123,
      endDateTime: '2024-01-16T10:00:00Z',
      actualReturnDateTime: '2024-01-16T15:00:00Z',
      item: { name: 'Power Drill' },
    };
    const owner = {
      firstName: 'John',
      lastName: 'Doe',
      email: 'john@example.com',
    };
    const renter = {
      firstName: 'Jane',
      lastName: 'Smith',
      email: 'jane@example.com',
    };
    const lateCalculation = {
      lateHours: 5,
      lateFee: 25.00,
    };

    it('should send late return notification with correct variables', async () => {
      const result = await service.sendLateReturnToCustomerService(
        rental,
        owner,
        renter,
        lateCalculation
      );

      expect(result.success).toBe(true);
      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'lateReturnToCS',
        expect.objectContaining({
          rentalId: 123,
          itemName: 'Power Drill',
          ownerName: 'John Doe',
          ownerEmail: 'john@example.com',
          renterName: 'Jane Smith',
          renterEmail: 'jane@example.com',
          hoursLate: '5.0',
          lateFee: '25.00',
        })
      );
      expect(service.emailClient.sendEmail).toHaveBeenCalledWith(
        'support@example.com',
        'Late Return Detected - Action Required',
        expect.any(String)
      );
    });

    it('should return error when customer service email is not configured', async () => {
      delete process.env.CUSTOMER_SUPPORT_EMAIL;

      const result = await service.sendLateReturnToCustomerService(
        rental,
        owner,
        renter,
        lateCalculation
      );

      expect(result.success).toBe(false);
      expect(result.error).toBe('No customer service email configured');
      expect(service.emailClient.sendEmail).not.toHaveBeenCalled();
    });

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

      const result = await service.sendLateReturnToCustomerService(
        rental,
        owner,
        renter,
        lateCalculation
      );

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

  describe('sendDamageReportToCustomerService', () => {
    const rental = {
      id: 123,
      item: { name: 'Power Drill' },
    };
    const owner = {
      firstName: 'John',
      lastName: 'Doe',
      email: 'john@example.com',
    };
    const renter = {
      firstName: 'Jane',
      lastName: 'Smith',
      email: 'jane@example.com',
    };
    const damageAssessment = {
      description: 'Drill bit broken',
      canBeFixed: true,
      repairCost: 30,
      needsReplacement: false,
      replacementCost: null,
      feeCalculation: {
        type: 'repair',
        amount: 30,
      },
      proofOfOwnership: ['receipt.jpg'],
    };

    it('should send damage report with correct variables', async () => {
      const result = await service.sendDamageReportToCustomerService(
        rental,
        owner,
        renter,
        damageAssessment
      );

      expect(result.success).toBe(true);
      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'damageReportToCS',
        expect.objectContaining({
          rentalId: 123,
          itemName: 'Power Drill',
          ownerName: 'John Doe',
          ownerEmail: 'john@example.com',
          renterName: 'Jane Smith',
          renterEmail: 'jane@example.com',
          damageDescription: 'Drill bit broken',
          canBeFixed: 'Yes',
          repairCost: '30.00',
          needsReplacement: 'No',
          feeTypeDescription: 'Repair Cost',
          damageFee: '30.00',
          lateFee: '0.00',
          totalFees: '30.00',
          hasProofOfOwnership: 'Yes',
        })
      );
      expect(service.emailClient.sendEmail).toHaveBeenCalledWith(
        'support@example.com',
        'Damage Report Filed - Action Required',
        expect.any(String)
      );
    });

    it('should include late fee when provided', async () => {
      const lateCalculation = { lateFee: 15 };

      await service.sendDamageReportToCustomerService(
        rental,
        owner,
        renter,
        damageAssessment,
        lateCalculation
      );

      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'damageReportToCS',
        expect.objectContaining({
          lateFee: '15.00',
          totalFees: '45.00',
        })
      );
    });

    it('should handle replacement fee type', async () => {
      const replacementAssessment = {
        ...damageAssessment,
        canBeFixed: false,
        needsReplacement: true,
        replacementCost: 150,
        feeCalculation: {
          type: 'replacement',
          amount: 150,
        },
      };

      await service.sendDamageReportToCustomerService(
        rental,
        owner,
        renter,
        replacementAssessment
      );

      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'damageReportToCS',
        expect.objectContaining({
          feeTypeDescription: 'Replacement Cost',
          needsReplacement: 'Yes',
          replacementCost: '150.00',
        })
      );
    });

    it('should handle unknown fee type', async () => {
      const unknownTypeAssessment = {
        ...damageAssessment,
        feeCalculation: {
          type: 'other',
          amount: 50,
        },
      };

      await service.sendDamageReportToCustomerService(
        rental,
        owner,
        renter,
        unknownTypeAssessment
      );

      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'damageReportToCS',
        expect.objectContaining({
          feeTypeDescription: 'Damage Assessment Fee',
        })
      );
    });

    it('should indicate no proof of ownership when not provided', async () => {
      const noProofAssessment = {
        ...damageAssessment,
        proofOfOwnership: [],
      };

      await service.sendDamageReportToCustomerService(
        rental,
        owner,
        renter,
        noProofAssessment
      );

      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'damageReportToCS',
        expect.objectContaining({
          hasProofOfOwnership: 'No',
        })
      );
    });

    it('should return error when customer service email is not configured', async () => {
      delete process.env.CUSTOMER_SUPPORT_EMAIL;

      const result = await service.sendDamageReportToCustomerService(
        rental,
        owner,
        renter,
        damageAssessment
      );

      expect(result.success).toBe(false);
      expect(result.error).toBe('No customer service email configured');
    });

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

      const result = await service.sendDamageReportToCustomerService(
        rental,
        owner,
        renter,
        damageAssessment
      );

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

  describe('sendLostItemToCustomerService', () => {
    const rental = {
      id: 123,
      endDateTime: '2024-01-16T10:00:00Z',
      itemLostReportedAt: '2024-01-17T10:00:00Z',
      item: {
        name: 'Power Drill',
        replacementCost: 200,
      },
    };
    const owner = {
      firstName: 'John',
      lastName: 'Doe',
      email: 'john@example.com',
    };
    const renter = {
      firstName: 'Jane',
      lastName: 'Smith',
      email: 'jane@example.com',
    };

    it('should send lost item notification with correct variables', async () => {
      const result = await service.sendLostItemToCustomerService(rental, owner, renter);

      expect(result.success).toBe(true);
      expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
        'lostItemToCS',
        expect.objectContaining({
          rentalId: 123,
          itemName: 'Power Drill',
          ownerName: 'John Doe',
          ownerEmail: 'john@example.com',
          renterName: 'Jane Smith',
          renterEmail: 'jane@example.com',
          replacementCost: '200.00',
        })
      );
      expect(service.emailClient.sendEmail).toHaveBeenCalledWith(
        'support@example.com',
        'Lost Item Claim Filed - Action Required',
        expect.any(String)
      );
    });

    it('should return error when customer service email is not configured', async () => {
      delete process.env.CUSTOMER_SUPPORT_EMAIL;

      const result = await service.sendLostItemToCustomerService(rental, owner, renter);

      expect(result.success).toBe(false);
      expect(result.error).toBe('No customer service email configured');
      expect(service.emailClient.sendEmail).not.toHaveBeenCalled();
    });

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

      const result = await service.sendLostItemToCustomerService(rental, owner, renter);

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