import { BadRequestException, Injectable } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';

export const NOTIFICATION_TYPES = ['assignment', 'mention', 'risk_alert', 'overdue_item'] as const;
export type NotificationType = (typeof NOTIFICATION_TYPES)[number];

export interface NotificationListQuery {
  recipientId: string;
  unreadOnly?: boolean;
  limit?: number;
}

export interface NotificationCreateInput {
  recipientId: string;
  actorId?: string | null;
  type: NotificationType;
  title: string;
  body?: string;
  resourceType: string;
  resourceId: string;
  resourceVersionId?: string | null;
  productId?: string | null;
  projectId?: string | null;
  versionId?: string | null;
  metadata?: unknown;
}

@Injectable()
export class NotificationService {
  constructor(private readonly prisma: PrismaService) {}

  list(query: NotificationListQuery) {
    const recipientId = requireText(query.recipientId, 'recipientId');
    return this.prisma.notification.findMany({
      where: {
        recipientId,
        ...(query.unreadOnly ? { readAt: null } : {}),
      },
      orderBy: { createdAt: 'desc' },
      take: normalizeLimit(query.limit),
    });
  }

  create(input: NotificationCreateInput) {
    const data = normalizeNotificationInput(input);
    return this.prisma.notification.create({ data });
  }

  async createMany(items: NotificationCreateInput[]) {
    const data = items.map(normalizeNotificationInput);
    if (data.length === 0) return { count: 0 };
    return this.prisma.notification.createMany({ data });
  }

  markRead(id: string, recipientId: string) {
    return this.prisma.notification.updateMany({
      where: { id: requireText(id, 'id'), recipientId: requireText(recipientId, 'recipientId'), readAt: null },
      data: { readAt: new Date() },
    });
  }

  markAllRead(recipientId: string) {
    return this.prisma.notification.updateMany({
      where: { recipientId: requireText(recipientId, 'recipientId'), readAt: null },
      data: { readAt: new Date() },
    });
  }
}

function normalizeNotificationInput(input: NotificationCreateInput) {
  if (!NOTIFICATION_TYPES.includes(input.type)) {
    throw new BadRequestException(`Unsupported notification type: ${input.type}`);
  }
  return {
    recipientId: requireText(input.recipientId, 'recipientId'),
    actorId: input.actorId ?? null,
    type: input.type,
    title: requireText(input.title, 'title'),
    body: input.body ?? '',
    resourceType: requireText(input.resourceType, 'resourceType'),
    resourceId: requireText(input.resourceId, 'resourceId'),
    resourceVersionId: input.resourceVersionId ?? null,
    productId: input.productId ?? null,
    projectId: input.projectId ?? null,
    versionId: input.versionId ?? null,
    metadata: input.metadata ?? {},
  };
}

function normalizeLimit(limit?: number): number {
  if (!Number.isFinite(limit)) return 50;
  return Math.max(1, Math.min(100, Math.floor(limit as number)));
}

function requireText(value: string | undefined | null, field: string): string {
  const normalized = value?.trim();
  if (!normalized) throw new BadRequestException(`${field} is required`);
  return normalized;
}
