// Mock CouchDB service before importing Event model
jest.mock('../../services/couchdbService', () => ({
  createDocument: jest.fn(),
  updateDocument: jest.fn(),
  getById: jest.fn(),
  find: jest.fn(),
  findByType: jest.fn(),
  findDocumentById: jest.fn(),
  update: jest.fn(),
  delete: jest.fn(),
  initialize: jest.fn(),
  isReady: jest.fn().mockReturnValue(true),
  shutdown: jest.fn()
}));

const Event = require('../../models/Event');
const couchdbService = require('../../services/couchdbService');

describe('Event Model', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    // Reset all mocks to ensure clean state
    couchdbService.createDocument.mockReset();
    couchdbService.findDocumentById.mockReset();
    couchdbService.updateDocument.mockReset();
    couchdbService.findByType.mockReset();
    couchdbService.getById.mockReset();
    couchdbService.find.mockReset();
    couchdbService.update.mockReset();
    
    // Set up default implementations for tests that don't override them
    couchdbService.createDocument.mockImplementation((doc) => Promise.resolve({
      _id: `test_${Date.now()}`,
      _rev: '1-test',
      ...doc
    }));
  });

  describe('Schema Validation', () => {
    it('should create a valid event', async () => {
      const eventData = {
        title: 'Community Cleanup',
        description: 'Join us for a street cleanup event',
        date: '2023-12-25T10:00:00.000Z',
        location: 'Main Street Park',
      };

      const mockCreated = {
        _id: 'event_123',
        _rev: '1-abc',
        type: 'event',
        ...eventData,
        participants: [],
        participantsCount: 0,
        status: 'upcoming',
        createdAt: '2023-01-01T00:00:00.000Z',
        updatedAt: '2023-01-01T00:00:00.000Z'
      };

      couchdbService.createDocument.mockResolvedValue(mockCreated);

      const event = await Event.create(eventData);

      expect(event._id).toBeDefined();
      expect(event.title).toBe(eventData.title);
      expect(event.description).toBe(eventData.description);
      expect(event.date).toBe(eventData.date);
      expect(event.location).toBe(eventData.location);
      expect(event.status).toBe('upcoming');
      expect(event.participants).toEqual([]);
      expect(event.participantsCount).toBe(0);
    });

    it('should require title field', async () => {
      const eventData = {
        description: 'Event without title',
        date: '2023-12-01T10:00:00.000Z',
        location: 'Main Street Park',
      };

      expect(() => new Event(eventData)).toThrow();
    });

    it('should require description field', async () => {
      const eventData = {
        title: 'Event without description',
        date: '2023-12-01T10:00:00.000Z',
        location: 'Main Street Park',
      };

      expect(() => new Event(eventData)).toThrow();
    });

    it('should require date field', async () => {
      const eventData = {
        title: 'Event without date',
        description: 'Event description',
        location: 'Main Street Park',
      };

      expect(() => new Event(eventData)).toThrow();
    });

    it('should require location field', async () => {
      const eventData = {
        title: 'Event without location',
        description: 'Event description',
        date: '2023-12-01T10:00:00.000Z',
      };

      expect(() => new Event(eventData)).toThrow();
    });
  });

  describe('Status Field', () => {
    it('should default status to upcoming', async () => {
      const eventData = {
        title: 'Status Test Event',
        description: 'Testing default status',
        date: '2023-12-01T10:00:00.000Z',
        location: 'Test Location',
      };

      const mockCreated = {
        _id: 'event_123',
        _rev: '1-abc',
        type: 'event',
        ...eventData,
        participants: [],
        status: 'upcoming',
        createdAt: '2023-01-01T00:00:00.000Z',
        updatedAt: '2023-01-01T00:00:00.000Z'
      };

      couchdbService.createDocument.mockResolvedValue(mockCreated);

      const event = await Event.create(eventData);

      expect(event.status).toBe('upcoming');
    });

    const validStatuses = ['upcoming', 'ongoing', 'completed', 'cancelled'];

    validStatuses.forEach(status => {
      it(`should accept "${status}" as valid status`, async () => {
        const eventData = {
          title: `${status} Event`,
          description: `Testing ${status} status`,
          date: '2023-12-01T10:00:00.000Z',
          location: 'Test Location',
          status,
        };

        const mockCreated = {
          _id: 'event_123',
          _rev: '1-abc',
          type: 'event',
          ...eventData,
          participants: [],
          createdAt: '2023-01-01T00:00:00.000Z',
          updatedAt: '2023-01-01T00:00:00.000Z'
        };

        couchdbService.createDocument.mockResolvedValue(mockCreated);

        const event = await Event.create(eventData);

        expect(event.status).toBe(status);
      });
    });
  });

  describe('Participants', () => {
    it('should start with empty participants array', async () => {
      const eventData = {
        title: 'Empty Participants Event',
        description: 'Testing empty participants',
        date: '2023-12-01T10:00:00.000Z',
        location: 'Test Location',
      };

      const mockCreated = {
        _id: 'event_123',
        _rev: '1-abc',
        type: 'event',
        ...eventData,
        participants: [],
        status: 'upcoming',
        createdAt: '2023-01-01T00:00:00.000Z',
        updatedAt: '2023-01-01T00:00:00.000Z'
      };

      couchdbService.createDocument.mockResolvedValue(mockCreated);

      const event = await Event.create(eventData);

      expect(event.participants).toEqual([]);
      expect(event.participants).toHaveLength(0);
    });

    it('should allow adding participants', async () => {
      const eventData = {
        title: 'Event with Participants',
        description: 'Testing participants',
        date: '2023-12-01T10:00:00.000Z',
        location: 'Test Location',
        participants: [
          {
            userId: 'user_123',
            name: 'Participant 1',
            profilePicture: '',
            joinedAt: '2023-11-01T10:00:00.000Z'
          }
        ]
      };

      const mockCreated = {
        _id: 'event_123',
        _rev: '1-abc',
        type: 'event',
        ...eventData,
        status: 'upcoming',
        createdAt: '2023-01-01T00:00:00.000Z',
        updatedAt: '2023-01-01T00:00:00.000Z'
      };

      couchdbService.createDocument.mockResolvedValue(mockCreated);

      const event = await Event.create(eventData);

      expect(event.participants).toHaveLength(1);
      expect(event.participants[0].userId).toBe('user_123');
      expect(event.participants[0].name).toBe('Participant 1');
    });

    it('should allow multiple participants', async () => {
      const eventData = {
        title: 'Popular Event',
        description: 'Testing multiple participants',
        date: '2023-12-01T10:00:00.000Z',
        location: 'Test Location',
        participants: [
          {
            userId: 'user_123',
            name: 'Participant 1',
            profilePicture: '',
            joinedAt: '2023-11-01T10:00:00.000Z'
          },
          {
            userId: 'user_456',
            name: 'Participant 2',
            profilePicture: '',
            joinedAt: '2023-11-02T10:00:00.000Z'
          }
        ]
      };

      const mockCreated = {
        _id: 'event_123',
        _rev: '1-abc',
        type: 'event',
        ...eventData,
        status: 'upcoming',
        createdAt: '2023-01-01T00:00:00.000Z',
        updatedAt: '2023-01-01T00:00:00.000Z'
      };

      couchdbService.createDocument.mockResolvedValue(mockCreated);

      const event = await Event.create(eventData);

      expect(event.participants).toHaveLength(2);
    });
  });

  describe('Organizer', () => {
    it('should store organizer information', async () => {
      const eventData = {
        title: 'Organizer Event',
        description: 'Testing organizer',
        date: '2023-12-01T10:00:00.000Z',
        location: 'Test Location',
        organizer: {
          userId: 'user_123',
          name: 'Organizer User',
          profilePicture: 'https://example.com/pic.jpg'
        }
      };

      const mockCreated = {
        _id: 'event_123',
        _rev: '1-abc',
        type: 'event',
        ...eventData,
        participants: [],
        status: 'upcoming',
        createdAt: '2023-01-01T00:00:00.000Z',
        updatedAt: '2023-01-01T00:00:00.000Z'
      };

      couchdbService.createDocument.mockResolvedValue(mockCreated);

      const event = await Event.create(eventData);

      expect(event.organizer).toBeDefined();
      expect(event.organizer.userId).toBe('user_123');
      expect(event.organizer.name).toBe('Organizer User');
      expect(event.organizer.profilePicture).toBe('https://example.com/pic.jpg');
    });
  });

  describe('Timestamps', () => {
    it('should automatically set createdAt and updatedAt', async () => {
      const eventData = {
        title: 'Timestamp Event',
        description: 'Testing timestamps',
        date: '2023-12-01T10:00:00.000Z',
        location: 'Test Location',
      };

      const mockCreated = {
        _id: 'event_123',
        _rev: '1-abc',
        type: 'event',
        ...eventData,
        participants: [],
        status: 'upcoming',
        createdAt: '2023-01-01T00:00:00.000Z',
        updatedAt: '2023-01-01T00:00:00.000Z'
      };

      couchdbService.createDocument.mockResolvedValue(mockCreated);

      const event = await Event.create(eventData);

      expect(event.createdAt).toBeDefined();
      expect(event.updatedAt).toBeDefined();
      expect(typeof event.createdAt).toBe('string');
      expect(typeof event.updatedAt).toBe('string');
    });

it('should update updatedAt on modification', async () => {
      const eventData = {
        title: 'Timestamp Event',
        description: 'Testing timestamps',
        date: '2023-12-01T10:00:00.000Z',
        location: 'Test Location',
        participants: [],
        status: 'upcoming',
        createdAt: '2023-01-01T00:00:00.000Z',
        updatedAt: '2023-01-01T00:00:00.000Z'
      };

      const mockEvent = {
        _id: 'event_123',
        _rev: '1-abc',
        type: 'event',
        ...eventData,
        participants: [],
        status: 'upcoming',
        createdAt: '2023-01-01T00:00:00.000Z',
        updatedAt: '2023-01-01T00:00:00.000Z'
      };

      couchdbService.getById.mockResolvedValue(mockEvent);
      couchdbService.updateDocument.mockResolvedValue({
        ...mockEvent,
        status: 'completed',
        _rev: '2-def'
      });

      const event = await Event.findById('event_123');
      const originalUpdatedAt = event.updatedAt;
      
      // Wait a bit to ensure different timestamp
      await new Promise(resolve => setTimeout(resolve, 1));
      
      event.status = 'completed';
      await event.save();

      expect(event.updatedAt).not.toBe(originalUpdatedAt);
      expect(event.updatedAt).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/);
    });
  });

  describe('Date Validation', () => {
    it('should accept valid date strings', async () => {
      const validDates = [
        '2023-12-01T10:00:00.000Z',
        '2024-01-15T14:30:00.000Z',
        '2023-11-30T09:00:00.000Z'
      ];

      for (const date of validDates) {
        const eventData = {
          title: `Event on ${date}`,
          description: 'Testing valid dates',
          date,
          location: 'Test Location',
        };

        const mockCreated = {
          _id: 'event_123',
          _rev: '1-abc',
          type: 'event',
          ...eventData,
          participants: [],
          status: 'upcoming',
          createdAt: '2023-01-01T00:00:00.000Z',
          updatedAt: '2023-01-01T00:00:00.000Z'
        };

        couchdbService.createDocument.mockResolvedValue(mockCreated);

        const event = await Event.create(eventData);

        expect(event.date).toBe(date);
      }
    });
  });

  describe('Static Methods', () => {
    it('should find event by ID', async () => {
      const mockEvent = {
        _id: 'event_123',
        _rev: '1-abc',
        type: 'event',
        title: 'Test Event',
        description: 'Test description',
        date: '2023-12-01T10:00:00.000Z',
        location: 'Test Location',
        participants: [],
        status: 'upcoming',
        createdAt: '2023-01-01T00:00:00.000Z',
        updatedAt: '2023-01-01T00:00:00.000Z'
      };

      couchdbService.getById.mockResolvedValue(mockEvent);

      const event = await Event.findById('event_123');
      expect(event).toBeDefined();
      expect(event._id).toBe('event_123');
      expect(event.title).toBe('Test Event');
    });

    it('should return null when event not found', async () => {
      couchdbService.getById.mockResolvedValue(null);

      const event = await Event.findById('nonexistent');
      expect(event).toBeNull();
    });
  });
});
