import { Injectable } from '@nestjs/common';
import { type Prisma } from '@prisma/client';
import { PrismaService } from '@modules/shared';
import type { MessageEntity } from '../../domain/entities/message.entity';
import type {
  IMessageRepository,
  CreateMessageDto,
} from '../../domain/repositories/message.repository';
import type { MessageType } from '../../domain/value-objects/message-type.vo';

@Injectable()
export class PrismaMessageRepository implements IMessageRepository {
  constructor(private readonly prisma: PrismaService) {}

  async create(dto: CreateMessageDto): Promise<MessageEntity> {
    const record = await this.prisma.message.create({
      data: {
        conversationId: dto.conversationId,
        senderId: dto.senderId,
        type: dto.type,
        content: dto.content,
        metadata: (dto.metadata ?? undefined) as Prisma.InputJsonValue | undefined,
      },
    });
    return this.toEntity(record);
  }

  async findByConversationId(
    conversationId: string,
    limit = 50,
    before?: string,
  ): Promise<MessageEntity[]> {
    const records = await this.prisma.message.findMany({
      where: {
        conversationId,
        deletedAt: null,
        ...(before ? { createdAt: { lt: (await this.prisma.message.findUnique({ where: { id: before } }))?.createdAt } } : {}),
      },
      orderBy: { createdAt: 'desc' },
      take: limit,
    });
    return records.map((r) => this.toEntity(r));
  }

  async findById(id: string): Promise<MessageEntity | null> {
    const record = await this.prisma.message.findUnique({ where: { id } });
    return record ? this.toEntity(record) : null;
  }

  async softDelete(id: string, senderId: string): Promise<void> {
    await this.prisma.message.updateMany({
      where: { id, senderId },
      data: { deletedAt: new Date() },
    });
  }

  private toEntity(record: {
    id: string;
    conversationId: string;
    senderId: string;
    type: string;
    content: string;
    metadata: unknown;
    editedAt: Date | null;
    deletedAt: Date | null;
    createdAt: Date;
  }): MessageEntity {
    return {
      id: record.id,
      conversationId: record.conversationId,
      senderId: record.senderId,
      type: record.type as MessageType,
      content: record.content,
      metadata: record.metadata as Record<string, unknown> | null,
      editedAt: record.editedAt,
      deletedAt: record.deletedAt,
      createdAt: record.createdAt,
    };
  }
}
