import { Injectable } from '@nestjs/common';
import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service';
import { NotificationType, NotificationPriority, TargetType, Prisma } from '@prisma/client';

export interface CreateNotificationDto {
  title: string;
  content: string;
  type?: NotificationType;
  priority?: NotificationPriority;
  targetType?: TargetType;
  targetConfig?: {
    accountSequences?: string[];
  };
  imageUrl?: string;
  linkUrl?: string;
  requiresForceRead?: boolean;
  publishedAt?: string;
  expiresAt?: string;
}

export interface UpdateNotificationDto {
  title?: string;
  content?: string;
  type?: NotificationType;
  priority?: NotificationPriority;
  targetType?: TargetType;
  targetConfig?: {
    accountSequences?: string[];
  };
  imageUrl?: string | null;
  linkUrl?: string | null;
  isEnabled?: boolean;
  requiresForceRead?: boolean;
  publishedAt?: string | null;
  expiresAt?: string | null;
}

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

  /**
   * 创建通知
   */
  async create(dto: CreateNotificationDto) {
    const targetType = dto.targetType || 'ALL';

    return this.prisma.$transaction(async (tx) => {
      const notification = await tx.notification.create({
        data: {
          title: dto.title,
          content: dto.content,
          type: dto.type || 'SYSTEM',
          priority: dto.priority || 'NORMAL',
          targetType,
          imageUrl: dto.imageUrl || null,
          linkUrl: dto.linkUrl || null,
          requiresForceRead: dto.requiresForceRead ?? false,
          publishedAt: dto.publishedAt ? new Date(dto.publishedAt) : null,
          expiresAt: dto.expiresAt ? new Date(dto.expiresAt) : null,
        },
      });

      // SPECIFIC 目标：创建用户关联
      if (
        targetType === 'SPECIFIC' &&
        dto.targetConfig?.accountSequences?.length
      ) {
        await tx.notificationUserTarget.createMany({
          data: dto.targetConfig.accountSequences.map((accountSequence) => ({
            notificationId: notification.id,
            accountSequence,
          })),
        });
      }

      return this.findById(notification.id, tx);
    });
  }

  /**
   * 查询通知详情
   */
  async findById(id: string, tx?: any) {
    const db = tx || this.prisma;
    const notification = await db.notification.findUnique({
      where: { id },
      include: {
        userTargets: { select: { accountSequence: true } },
      },
    });
    if (!notification) return null;
    return this.formatNotification(notification);
  }

  /**
   * 管理端通知列表
   */
  async findAll(params?: {
    type?: NotificationType;
    limit?: number;
    offset?: number;
  }) {
    const where: Prisma.NotificationWhereInput = {};
    if (params?.type) where.type = params.type;

    const [notifications, total] = await Promise.all([
      this.prisma.notification.findMany({
        where,
        include: {
          userTargets: { select: { accountSequence: true } },
        },
        orderBy: { createdAt: 'desc' },
        take: params?.limit ?? 50,
        skip: params?.offset ?? 0,
      }),
      this.prisma.notification.count({ where }),
    ]);

    return {
      notifications: notifications.map((n) => this.formatNotification(n)),
      total,
    };
  }

  /**
   * 更新通知
   */
  async update(id: string, dto: UpdateNotificationDto) {
    return this.prisma.$transaction(async (tx) => {
      const data: any = {};
      if (dto.title !== undefined) data.title = dto.title;
      if (dto.content !== undefined) data.content = dto.content;
      if (dto.type !== undefined) data.type = dto.type;
      if (dto.priority !== undefined) data.priority = dto.priority;
      if (dto.targetType !== undefined) data.targetType = dto.targetType;
      if (dto.imageUrl !== undefined) data.imageUrl = dto.imageUrl;
      if (dto.linkUrl !== undefined) data.linkUrl = dto.linkUrl;
      if (dto.isEnabled !== undefined) data.isEnabled = dto.isEnabled;
      if (dto.requiresForceRead !== undefined)
        data.requiresForceRead = dto.requiresForceRead;
      if (dto.publishedAt !== undefined)
        data.publishedAt = dto.publishedAt ? new Date(dto.publishedAt) : null;
      if (dto.expiresAt !== undefined)
        data.expiresAt = dto.expiresAt ? new Date(dto.expiresAt) : null;

      await tx.notification.update({ where: { id }, data });

      // 如果更新了目标类型或目标配置，重建用户关联
      if (dto.targetType !== undefined || dto.targetConfig !== undefined) {
        await tx.notificationUserTarget.deleteMany({
          where: { notificationId: id },
        });

        const targetType = dto.targetType || (await tx.notification.findUnique({ where: { id }, select: { targetType: true } }))?.targetType;

        if (
          targetType === 'SPECIFIC' &&
          dto.targetConfig?.accountSequences?.length
        ) {
          await tx.notificationUserTarget.createMany({
            data: dto.targetConfig.accountSequences.map((accountSequence) => ({
              notificationId: id,
              accountSequence,
            })),
          });
        }
      }

      return this.findById(id, tx);
    });
  }

  /**
   * 删除通知
   */
  async delete(id: string) {
    await this.prisma.notification.delete({ where: { id } });
  }

  /**
   * 移动端：获取用户的通知列表（带已读状态）
   */
  async findNotificationsForUser(params: {
    userSerialNum: string;
    type?: NotificationType;
    limit?: number;
    offset?: number;
  }) {
    const now = new Date();

    const notifications = await this.prisma.notification.findMany({
      where: {
        isEnabled: true,
        ...(params.type && { type: params.type }),
        AND: [
          { OR: [{ publishedAt: null }, { publishedAt: { lte: now } }] },
          { OR: [{ expiresAt: null }, { expiresAt: { gt: now } }] },
          {
            OR: [
              { targetType: 'ALL' },
              {
                targetType: 'SPECIFIC',
                userTargets: {
                  some: { accountSequence: params.userSerialNum },
                },
              },
            ],
          },
        ],
      },
      include: {
        reads: {
          where: { userSerialNum: params.userSerialNum },
          take: 1,
        },
      },
      orderBy: [{ priority: 'desc' }, { publishedAt: 'desc' }],
      take: params.limit ?? 50,
      skip: params.offset ?? 0,
    });

    return notifications.map((n) => ({
      id: n.id,
      title: n.title,
      content: n.content,
      type: n.type,
      priority: n.priority,
      imageUrl: n.imageUrl,
      linkUrl: n.linkUrl,
      publishedAt: n.publishedAt,
      isRead: n.reads.length > 0,
      readAt: n.reads[0]?.readAt ?? null,
      requiresForceRead: n.requiresForceRead,
    }));
  }

  /**
   * 移动端：获取未读通知数量
   */
  async countUnreadForUser(userSerialNum: string): Promise<number> {
    const now = new Date();

    return this.prisma.notification.count({
      where: {
        isEnabled: true,
        reads: {
          none: { userSerialNum },
        },
        AND: [
          { OR: [{ publishedAt: null }, { publishedAt: { lte: now } }] },
          { OR: [{ expiresAt: null }, { expiresAt: { gt: now } }] },
          {
            OR: [
              { targetType: 'ALL' },
              {
                targetType: 'SPECIFIC',
                userTargets: {
                  some: { accountSequence: userSerialNum },
                },
              },
            ],
          },
        ],
      },
    });
  }

  /**
   * 移动端：标记通知为已读
   */
  async markAsRead(notificationId: string, userSerialNum: string) {
    await this.prisma.notificationRead.upsert({
      where: {
        notificationId_userSerialNum: {
          notificationId,
          userSerialNum,
        },
      },
      create: { notificationId, userSerialNum },
      update: {},
    });
  }

  /**
   * 移动端：标记全部已读
   */
  async markAllAsRead(userSerialNum: string) {
    const now = new Date();

    const unreadNotifications = await this.prisma.notification.findMany({
      where: {
        isEnabled: true,
        reads: {
          none: { userSerialNum },
        },
        AND: [
          { OR: [{ publishedAt: null }, { publishedAt: { lte: now } }] },
          { OR: [{ expiresAt: null }, { expiresAt: { gt: now } }] },
          {
            OR: [
              { targetType: 'ALL' },
              {
                targetType: 'SPECIFIC',
                userTargets: {
                  some: { accountSequence: userSerialNum },
                },
              },
            ],
          },
        ],
      },
      select: { id: true },
    });

    if (unreadNotifications.length > 0) {
      await this.prisma.notificationRead.createMany({
        data: unreadNotifications.map((n) => ({
          notificationId: n.id,
          userSerialNum,
        })),
        skipDuplicates: true,
      });
    }
  }

  /**
   * 格式化通知（包含目标配置）
   */
  private formatNotification(notification: any) {
    const targetConfig =
      notification.targetType === 'SPECIFIC' && notification.userTargets?.length
        ? {
            accountSequences: notification.userTargets.map(
              (t: any) => t.accountSequence,
            ),
          }
        : null;

    return {
      id: notification.id,
      title: notification.title,
      content: notification.content,
      type: notification.type,
      priority: notification.priority,
      targetType: notification.targetType,
      targetConfig,
      imageUrl: notification.imageUrl,
      linkUrl: notification.linkUrl,
      isEnabled: notification.isEnabled,
      requiresForceRead: notification.requiresForceRead,
      publishedAt: notification.publishedAt,
      expiresAt: notification.expiresAt,
      createdAt: notification.createdAt,
    };
  }
}
