import { Notification } from '@core/notifications/domain/entities/Notification';
import type { NotificationRepository } from '@core/notifications/domain/repositories/NotificationRepository';
import type { NotificationType } from '@core/notifications/domain/types/NotificationTypes';
import type { DataSource } from 'typeorm';
import { NotificationOrmEntity } from '../entities/NotificationOrmEntity';
import { NotificationOrmMapper } from '../mappers/NotificationOrmMapper';

export class TypeOrmNotificationRepository implements NotificationRepository {
  constructor(
    private readonly dataSource: DataSource,
    private readonly mapper: NotificationOrmMapper,
  ) {}

  async findById(id: string): Promise<Notification | null> {
    const repo = this.dataSource.getRepository(NotificationOrmEntity);
    const entity = await repo.findOne({ where: { id } });
    return entity ? this.mapper.toDomain(entity) : null;
  }

  async findByRecipientId(recipientId: string): Promise<Notification[]> {
    const repo = this.dataSource.getRepository(NotificationOrmEntity);
    const entities = await repo.find({
      where: { recipientId },
      order: { createdAt: 'DESC' },
    });
    return entities.map(entity => this.mapper.toDomain(entity));
  }

  async findUnreadByRecipientId(recipientId: string): Promise<Notification[]> {
    const repo = this.dataSource.getRepository(NotificationOrmEntity);
    const entities = await repo.find({
      where: { recipientId, status: 'unread' },
      order: { createdAt: 'DESC' },
    });
    return entities.map(entity => this.mapper.toDomain(entity));
  }

  async findByRecipientIdAndType(recipientId: string, type: NotificationType): Promise<Notification[]> {
    const repo = this.dataSource.getRepository(NotificationOrmEntity);
    const entities = await repo.find({
      where: { recipientId, type },
      order: { createdAt: 'DESC' },
    });
    return entities.map(entity => this.mapper.toDomain(entity));
  }

  async countUnreadByRecipientId(recipientId: string): Promise<number> {
    const repo = this.dataSource.getRepository(NotificationOrmEntity);
    return await repo.count({
      where: { recipientId, status: 'unread' },
    });
  }

  async create(notification: Notification): Promise<void> {
    const repo = this.dataSource.getRepository(NotificationOrmEntity);
    const entity = this.mapper.toOrmEntity(notification);
    await repo.save(entity);
  }

  async update(notification: Notification): Promise<void> {
    const repo = this.dataSource.getRepository(NotificationOrmEntity);
    const entity = this.mapper.toOrmEntity(notification);
    await repo.save(entity);
  }

  async delete(id: string): Promise<void> {
    const repo = this.dataSource.getRepository(NotificationOrmEntity);
    await repo.delete({ id });
  }

  async deleteAllByRecipientId(recipientId: string): Promise<void> {
    const repo = this.dataSource.getRepository(NotificationOrmEntity);
    await repo.delete({ recipientId });
  }

  async markAllAsReadByRecipientId(recipientId: string): Promise<void> {
    const repo = this.dataSource.getRepository(NotificationOrmEntity);
    await repo.update(
      { recipientId, status: 'unread' },
      { status: 'read', readAt: new Date() },
    );
  }
}