// Mock dependencies BEFORE requiring modules
jest.mock('../../../models');
jest.mock('../../../services/lateReturnService');
jest.mock('../../../services/email', () => ({
  customerService: {
    sendDamageReportToCustomerService: jest.fn().mockResolvedValue()
  }
}));
jest.mock('../../../config/aws', () => ({
  getAWSConfig: jest.fn(() => ({ region: 'us-east-1' })),
  getAWSCredentials: jest.fn()
}));

const DamageAssessmentService = require('../../../services/damageAssessmentService');
const { Rental, Item } = require('../../../models');
const LateReturnService = require('../../../services/lateReturnService');
const emailService = require('../../../services/email');

describe('DamageAssessmentService', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('processDamageAssessment', () => {
    let mockRental;
    let mockDamageInfo;

    beforeEach(() => {
      // Reset mockRental for each test to avoid state pollution
      // Active status is computed: confirmed + startDateTime in the past
      const pastDate = new Date();
      pastDate.setHours(pastDate.getHours() - 1); // 1 hour ago
      mockRental = {
        id: 'rental-123',
        ownerId: 'owner-789',
        renterId: 'renter-456',
        status: 'confirmed',
        startDateTime: pastDate,
        item: { name: 'Test Camera', dailyRate: 100 },
        update: jest.fn().mockResolvedValue({
          id: 'rental-123',
          status: 'damaged',
          damageFees: 500
        })
      };

      mockDamageInfo = {
        description: 'Camera lens is cracked and unusable',
        canBeFixed: false,
        needsReplacement: true,
        replacementCost: 500,
        photos: ['photo1.jpg', 'photo2.jpg'],
        proofOfOwnership: ['receipt.pdf']
      };

      Rental.findByPk.mockResolvedValue(mockRental);
      LateReturnService.processLateReturn.mockResolvedValue({
        lateCalculation: { lateFee: 0, isLate: false }
      });
      emailService.customerService.sendDamageReportToCustomerService.mockResolvedValue();
    });

    it('should process damage assessment for replacement', async () => {
      const result = await DamageAssessmentService.processDamageAssessment(
        'rental-123',
        mockDamageInfo,
        'owner-789'
      );

      expect(mockRental.update).toHaveBeenCalledWith({
        status: 'damaged',
        damageFees: 500,
        damageAssessment: expect.objectContaining({
          description: 'Camera lens is cracked and unusable',
          canBeFixed: false,
          needsReplacement: true,
          replacementCost: 500,
          feeCalculation: expect.objectContaining({
            type: 'replacement',
            amount: 500
          })
        })
      });

      expect(emailService.customerService.sendDamageReportToCustomerService).toHaveBeenCalled();
      expect(result.totalAdditionalFees).toBe(500);
    });

    it('should process damage assessment for repair', async () => {
      const repairInfo = {
        description: 'Lens needs professional cleaning and adjustment',
        canBeFixed: true,
        needsReplacement: false,
        repairCost: 150
      };

      mockRental.update.mockResolvedValue({
        ...mockRental,
        status: 'damaged',
        damageFees: 150
      });

      const result = await DamageAssessmentService.processDamageAssessment(
        'rental-123',
        repairInfo,
        'owner-789'
      );

      expect(mockRental.update).toHaveBeenCalledWith({
        status: 'damaged',
        damageFees: 150,
        damageAssessment: expect.objectContaining({
          canBeFixed: true,
          needsReplacement: false,
          repairCost: 150,
          feeCalculation: expect.objectContaining({
            type: 'repair',
            amount: 150
          })
        })
      });

      expect(result.totalAdditionalFees).toBe(150);
    });

    it('should include late fees when provided', async () => {
      const actualReturnDateTime = new Date('2023-06-01T14:00:00Z');

      LateReturnService.processLateReturn.mockResolvedValue({
        lateCalculation: { lateFee: 50, isLate: true }
      });

      mockRental.update.mockResolvedValue({
        ...mockRental,
        status: 'damaged',
        damageFees: 500,
        lateFees: 50
      });

      const result = await DamageAssessmentService.processDamageAssessment(
        'rental-123',
        { ...mockDamageInfo, actualReturnDateTime },
        'owner-789'
      );

      expect(LateReturnService.processLateReturn).toHaveBeenCalledWith(
        'rental-123',
        actualReturnDateTime,
        'Item returned damaged: Camera lens is cracked and unusable'
      );

      expect(result.totalAdditionalFees).toBe(550); // 500 damage + 50 late fee
    });

    it('should throw error when rental not found', async () => {
      Rental.findByPk.mockResolvedValue(null);

      await expect(
        DamageAssessmentService.processDamageAssessment(
          'nonexistent',
          mockDamageInfo,
          'owner-789'
        )
      ).rejects.toThrow('Rental not found');
    });

    it('should validate authorization - only owner can report', async () => {
      await expect(
        DamageAssessmentService.processDamageAssessment(
          'rental-123',
          mockDamageInfo,
          'renter-456'
        )
      ).rejects.toThrow('Only the item owner can report damage');
    });

    it('should validate rental status - only active rentals', async () => {
      mockRental.status = 'completed';

      await expect(
        DamageAssessmentService.processDamageAssessment(
          'rental-123',
          mockDamageInfo,
          'owner-789'
        )
      ).rejects.toThrow('Can only assess damage for active rentals');
    });

    it('should validate required fields - description', async () => {
      await expect(
        DamageAssessmentService.processDamageAssessment(
          'rental-123',
          { ...mockDamageInfo, description: '' },
          'owner-789'
        )
      ).rejects.toThrow('Damage description is required');
    });

    it('should validate required fields - repair cost', async () => {
      await expect(
        DamageAssessmentService.processDamageAssessment(
          'rental-123',
          {
            description: 'Needs repair',
            canBeFixed: true,
            needsReplacement: false
          },
          'owner-789'
        )
      ).rejects.toThrow('Repair cost is required when item can be fixed');
    });

    it('should validate required fields - replacement cost', async () => {
      await expect(
        DamageAssessmentService.processDamageAssessment(
          'rental-123',
          {
            description: 'Needs replacement',
            canBeFixed: false,
            needsReplacement: true
          },
          'owner-789'
        )
      ).rejects.toThrow('Replacement cost is required when item needs replacement');
    });
  });
});