import {
  DuplicateReviewError,
  InvalidReviewError,
  ReviewNotEligibleError,
  ReviewNotFoundError,
} from '../domain/errors.js';
import type { OrderItemVerifier, ReviewsRepository } from '../domain/ports.js';
import type {
  ProductReviewAggregate,
  PublishedReview,
  Review,
  SubmitReviewCommand,
} from '../domain/review.js';

export class ReviewsService {
  constructor(
    private readonly repo: ReviewsRepository,
    private readonly verifier: OrderItemVerifier,
  ) {}

  async submit(command: SubmitReviewCommand): Promise<Review> {
    if (!Number.isInteger(command.rating) || command.rating < 1 || command.rating > 5) {
      throw new InvalidReviewError('Rating must be an integer 1..5');
    }
    const existing = await this.repo.findByOrderItemId(command.orderItemId);
    if (existing) throw new DuplicateReviewError();
    const eligible = await this.verifier.isDeliveredForUser(command.userId, command.orderItemId);
    if (!eligible) throw new ReviewNotEligibleError();
    const inserted = await this.repo.insert(command);
    if (!inserted) throw new DuplicateReviewError();
    return inserted;
  }

  async moderate(id: string, status: 'published' | 'rejected'): Promise<Review> {
    const updated = await this.repo.setStatus(id, status);
    if (!updated) throw new ReviewNotFoundError();
    return updated;
  }

  async listPublishedByProduct(
    productId: string,
  ): Promise<{ items: PublishedReview[]; aggregate: ProductReviewAggregate }> {
    const items = await this.repo.listPublishedByProduct(productId);
    const aggregate = await this.repo.aggregate(productId);
    return { items, aggregate };
  }

  async listAll(params?: { status?: string; limit?: number; offset?: number }) {
    return this.repo.listAll(params);
  }
}
