import { describe, it, expect } from 'vitest';
import { ReviewEntity } from '../entities/review.entity';
import { ReviewCreatedEvent } from '../events/review-created.event';
import { ReviewDeletedEvent } from '../events/review-deleted.event';
import { Rating } from '../value-objects/rating.vo';

describe('Reviews Domain', () => {
  describe('Rating', () => {
    it('creates valid rating', () => {
      const result = Rating.create(5);
      expect(result.isOk).toBe(true);
      expect(result.unwrap().value).toBe(5);
    });

    it('creates rating with minimum value', () => {
      const result = Rating.create(1);
      expect(result.isOk).toBe(true);
      expect(result.unwrap().value).toBe(1);
    });

    it('rejects rating below 1', () => {
      const result = Rating.create(0);
      expect(result.isErr).toBe(true);
    });

    it('rejects rating above 5', () => {
      const result = Rating.create(6);
      expect(result.isErr).toBe(true);
    });

    it('rejects non-integer rating', () => {
      const result = Rating.create(3.5);
      expect(result.isErr).toBe(true);
    });

    it('rejects negative rating', () => {
      const result = Rating.create(-1);
      expect(result.isErr).toBe(true);
    });
  });

  describe('ReviewCreatedEvent', () => {
    it('creates event with correct properties', () => {
      const event = new ReviewCreatedEvent('review-1', 'user-1', 'agent', 'agent-1', 5);

      expect(event.eventName).toBe('review.created');
      expect(event.aggregateId).toBe('review-1');
      expect(event.userId).toBe('user-1');
      expect(event.targetType).toBe('agent');
      expect(event.targetId).toBe('agent-1');
      expect(event.rating).toBe(5);
      expect(event.occurredAt).toBeInstanceOf(Date);
    });
  });

  describe('ReviewDeletedEvent', () => {
    it('creates event with correct properties', () => {
      const event = new ReviewDeletedEvent('review-1', 'user-1', 'agent', 'agent-1');

      expect(event.eventName).toBe('review.deleted');
      expect(event.aggregateId).toBe('review-1');
      expect(event.userId).toBe('user-1');
      expect(event.targetType).toBe('agent');
      expect(event.targetId).toBe('agent-1');
      expect(event.occurredAt).toBeInstanceOf(Date);
    });
  });

  describe('ReviewEntity', () => {
    it('creates new review with domain event', () => {
      const rating = Rating.create(4).unwrap();
      const review = ReviewEntity.createNew(
        'review-1',
        'user-1',
        'agent',
        'agent-1',
        rating,
        'Môi giới rất nhiệt tình',
      );

      expect(review.id).toBe('review-1');
      expect(review.userId).toBe('user-1');
      expect(review.targetType).toBe('agent');
      expect(review.targetId).toBe('agent-1');
      expect(review.rating.value).toBe(4);
      expect(review.comment).toBe('Môi giới rất nhiệt tình');

      const events = review.domainEvents;
      expect(events).toHaveLength(1);
      expect(events[0]).toBeInstanceOf(ReviewCreatedEvent);
    });

    it('creates review without comment', () => {
      const rating = Rating.create(3).unwrap();
      const review = ReviewEntity.createNew(
        'review-2',
        'user-2',
        'property',
        'prop-1',
        rating,
        null,
      );

      expect(review.comment).toBeNull();
    });

    it('emits ReviewDeletedEvent on markDeleted', () => {
      const rating = Rating.create(5).unwrap();
      const review = ReviewEntity.createNew(
        'review-3',
        'user-3',
        'agent',
        'agent-2',
        rating,
        null,
      );

      review.clearDomainEvents();
      review.markDeleted();

      const events = review.domainEvents;
      expect(events).toHaveLength(1);
      expect(events[0]).toBeInstanceOf(ReviewDeletedEvent);
      const deleteEvent = events[0] as ReviewDeletedEvent;
      expect(deleteEvent.userId).toBe('user-3');
      expect(deleteEvent.targetType).toBe('agent');
      expect(deleteEvent.targetId).toBe('agent-2');
    });
  });
});
