const request = require('supertest');
const express = require('express');

// Mock dependencies
jest.mock('../../../middleware/auth', () => ({
  authenticateToken: (req, res, next) => {
    req.user = { id: 'user-123' };
    next();
  },
}));

jest.mock('../../../services/conditionCheckService', () => ({
  submitConditionCheck: jest.fn(),
  getAvailableChecks: jest.fn(),
}));

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

jest.mock('../../../utils/s3KeyValidator', () => ({
  validateS3Keys: jest.fn().mockReturnValue({ valid: true }),
}));

jest.mock('../../../config/imageLimits', () => ({
  IMAGE_LIMITS: { conditionChecks: 10 },
}));

const ConditionCheckService = require('../../../services/conditionCheckService');
const { validateS3Keys } = require('../../../utils/s3KeyValidator');
const conditionCheckRoutes = require('../../../routes/conditionChecks');

const app = express();
app.use(express.json());
app.use('/condition-checks', conditionCheckRoutes);

// Error handler
app.use((err, req, res, next) => {
  res.status(500).json({ error: err.message });
});

describe('Condition Check Routes', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('POST /condition-checks/:rentalId', () => {
    const validConditionCheck = {
      checkType: 'pre_rental',
      notes: 'Item in good condition',
      imageFilenames: ['condition-checks/uuid1.jpg', 'condition-checks/uuid2.jpg'],
    };

    it('should submit a condition check successfully', async () => {
      const mockConditionCheck = {
        id: 'check-1',
        rentalId: 'rental-123',
        checkType: 'pre_rental',
        notes: 'Item in good condition',
        imageFilenames: validConditionCheck.imageFilenames,
        submittedBy: 'user-123',
        createdAt: new Date().toISOString(),
      };

      ConditionCheckService.submitConditionCheck.mockResolvedValue(mockConditionCheck);

      const response = await request(app)
        .post('/condition-checks/rental-123')
        .send(validConditionCheck);

      expect(response.status).toBe(201);
      expect(response.body.success).toBe(true);
      expect(response.body.conditionCheck).toMatchObject({
        id: 'check-1',
        checkType: 'pre_rental',
      });
      expect(ConditionCheckService.submitConditionCheck).toHaveBeenCalledWith(
        'rental-123',
        'pre_rental',
        'user-123',
        validConditionCheck.imageFilenames,
        'Item in good condition'
      );
    });

    it('should handle empty image array', async () => {
      const mockConditionCheck = {
        id: 'check-1',
        rentalId: 'rental-123',
        checkType: 'post_rental',
        imageFilenames: [],
      };

      ConditionCheckService.submitConditionCheck.mockResolvedValue(mockConditionCheck);

      const response = await request(app)
        .post('/condition-checks/rental-123')
        .send({
          checkType: 'post_rental',
          notes: 'No photos',
        });

      expect(response.status).toBe(201);
      expect(response.body.success).toBe(true);
      expect(ConditionCheckService.submitConditionCheck).toHaveBeenCalledWith(
        'rental-123',
        'post_rental',
        'user-123',
        [],
        'No photos'
      );
    });

    it('should reject invalid S3 keys', async () => {
      validateS3Keys.mockReturnValueOnce({
        valid: false,
        error: 'Invalid S3 key format',
        invalidKeys: ['invalid-key'],
      });

      const response = await request(app)
        .post('/condition-checks/rental-123')
        .send({
          checkType: 'pre_rental',
          imageFilenames: ['invalid-key'],
        });

      expect(response.status).toBe(400);
      expect(response.body.success).toBe(false);
      expect(response.body.error).toBe('Invalid S3 key format');
      expect(response.body.details).toContain('invalid-key');
    });

    it('should handle service errors', async () => {
      ConditionCheckService.submitConditionCheck.mockRejectedValue(
        new Error('Rental not found')
      );

      const response = await request(app)
        .post('/condition-checks/rental-123')
        .send(validConditionCheck);

      expect(response.status).toBe(400);
      expect(response.body.success).toBe(false);
      expect(response.body.error).toBe('Rental not found');
    });

    it('should handle non-array imageFilenames gracefully', async () => {
      const mockConditionCheck = {
        id: 'check-1',
        rentalId: 'rental-123',
        checkType: 'pre_rental',
        imageFilenames: [],
      };

      ConditionCheckService.submitConditionCheck.mockResolvedValue(mockConditionCheck);

      const response = await request(app)
        .post('/condition-checks/rental-123')
        .send({
          checkType: 'pre_rental',
          imageFilenames: 'not-an-array',
        });

      expect(response.status).toBe(201);
      // Should convert to empty array
      expect(ConditionCheckService.submitConditionCheck).toHaveBeenCalledWith(
        'rental-123',
        'pre_rental',
        'user-123',
        [],
        undefined
      );
    });
  });

  describe('GET /condition-checks', () => {
    it('should return available checks for specified rentals', async () => {
      const mockAvailableChecks = [
        {
          rentalId: 'rental-1',
          itemName: 'Camera',
          checkType: 'pre_rental',
          dueDate: '2024-01-10',
        },
        {
          rentalId: 'rental-2',
          itemName: 'Laptop',
          checkType: 'post_rental',
          dueDate: '2024-01-15',
        },
      ];

      ConditionCheckService.getAvailableChecks.mockResolvedValue(mockAvailableChecks);

      const response = await request(app)
        .get('/condition-checks?rentalIds=rental-1,rental-2');

      expect(response.status).toBe(200);
      expect(response.body.success).toBe(true);
      expect(response.body.availableChecks).toHaveLength(2);
      expect(response.body.availableChecks[0].itemName).toBe('Camera');
      expect(ConditionCheckService.getAvailableChecks).toHaveBeenCalledWith('user-123', ['rental-1', 'rental-2']);
    });

    it('should return empty array when no rentalIds provided', async () => {
      ConditionCheckService.getAvailableChecks.mockResolvedValue([]);

      const response = await request(app)
        .get('/condition-checks');

      expect(response.status).toBe(200);
      expect(response.body.success).toBe(true);
      expect(response.body.availableChecks).toHaveLength(0);
      expect(ConditionCheckService.getAvailableChecks).toHaveBeenCalledWith('user-123', []);
    });

    it('should handle service errors', async () => {
      ConditionCheckService.getAvailableChecks.mockRejectedValue(
        new Error('Database error')
      );

      const response = await request(app)
        .get('/condition-checks?rentalIds=rental-1');

      expect(response.status).toBe(500);
      expect(response.body.success).toBe(false);
      expect(response.body.error).toBe('Failed to fetch available checks');
    });
  });
});
