import { Injectable } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { PrismaService } from '../prisma/prisma.service';
import {
  ISystemActivityRepository,
  SystemActivityData,
  ActivityType,
} from '../../../domain/repositories';

@Injectable()
export class SystemActivityRepository implements ISystemActivityRepository {
  constructor(private readonly prisma: PrismaService) {}

  async create(activity: SystemActivityData): Promise<SystemActivityData> {
    const result = await this.prisma.systemActivity.create({
      data: {
        activityType: activity.activityType,
        title: activity.title,
        description: activity.description,
        icon: activity.icon || '📌',
        relatedUserId: activity.relatedUserId,
        relatedEntityId: activity.relatedEntityId,
        relatedEntityType: activity.relatedEntityType,
        metadata: activity.metadata as Prisma.InputJsonValue,
      },
    });

    return this.toDomain(result);
  }

  async createMany(activities: SystemActivityData[]): Promise<number> {
    const result = await this.prisma.systemActivity.createMany({
      data: activities.map((activity) => ({
        activityType: activity.activityType,
        title: activity.title,
        description: activity.description,
        icon: activity.icon || '📌',
        relatedUserId: activity.relatedUserId,
        relatedEntityId: activity.relatedEntityId,
        relatedEntityType: activity.relatedEntityType,
        metadata: activity.metadata as Prisma.InputJsonValue,
      })),
    });
    return result.count;
  }

  async findById(id: bigint): Promise<SystemActivityData | null> {
    const found = await this.prisma.systemActivity.findUnique({
      where: { id },
    });
    return found ? this.toDomain(found) : null;
  }

  async findRecent(limit: number): Promise<SystemActivityData[]> {
    const found = await this.prisma.systemActivity.findMany({
      take: limit,
      orderBy: { createdAt: 'desc' },
    });
    return found.map((item) => this.toDomain(item));
  }

  async findByType(
    type: ActivityType | string,
    limit = 20,
  ): Promise<SystemActivityData[]> {
    const found = await this.prisma.systemActivity.findMany({
      where: { activityType: type },
      take: limit,
      orderBy: { createdAt: 'desc' },
    });
    return found.map((item) => this.toDomain(item));
  }

  async findByUserId(
    userId: bigint,
    limit = 20,
  ): Promise<SystemActivityData[]> {
    const found = await this.prisma.systemActivity.findMany({
      where: { relatedUserId: userId },
      take: limit,
      orderBy: { createdAt: 'desc' },
    });
    return found.map((item) => this.toDomain(item));
  }

  async findByEntity(
    entityType: string,
    entityId: string,
    limit = 20,
  ): Promise<SystemActivityData[]> {
    const found = await this.prisma.systemActivity.findMany({
      where: {
        relatedEntityType: entityType,
        relatedEntityId: entityId,
      },
      take: limit,
      orderBy: { createdAt: 'desc' },
    });
    return found.map((item) => this.toDomain(item));
  }

  async findByDateRange(
    startDate: Date,
    endDate: Date,
    limit = 100,
  ): Promise<SystemActivityData[]> {
    const found = await this.prisma.systemActivity.findMany({
      where: {
        createdAt: {
          gte: startDate,
          lte: endDate,
        },
      },
      take: limit,
      orderBy: { createdAt: 'desc' },
    });
    return found.map((item) => this.toDomain(item));
  }

  async deleteBeforeDate(date: Date): Promise<number> {
    const result = await this.prisma.systemActivity.deleteMany({
      where: {
        createdAt: {
          lt: date,
        },
      },
    });
    return result.count;
  }

  async countByType(type: ActivityType | string): Promise<number> {
    return this.prisma.systemActivity.count({
      where: { activityType: type },
    });
  }

  async exists(
    activityType: ActivityType | string,
    entityType: string,
    entityId: string,
  ): Promise<boolean> {
    const count = await this.prisma.systemActivity.count({
      where: {
        activityType,
        relatedEntityType: entityType,
        relatedEntityId: entityId,
      },
    });
    return count > 0;
  }

  async createIfNotExists(activity: SystemActivityData): Promise<SystemActivityData | null> {
    // 先检查是否已存在
    if (activity.relatedEntityType && activity.relatedEntityId) {
      const alreadyExists = await this.exists(
        activity.activityType,
        activity.relatedEntityType,
        activity.relatedEntityId,
      );
      if (alreadyExists) {
        return null; // 已存在，跳过创建
      }
    }
    // 不存在则创建
    return this.create(activity);
  }

  private toDomain(
    record: Awaited<ReturnType<typeof this.prisma.systemActivity.findFirst>>,
  ): SystemActivityData {
    if (!record) {
      throw new Error('Record is null');
    }
    return {
      id: record.id,
      activityType: record.activityType as ActivityType,
      title: record.title,
      description: record.description,
      icon: record.icon,
      relatedUserId: record.relatedUserId ?? undefined,
      relatedEntityId: record.relatedEntityId ?? undefined,
      relatedEntityType: record.relatedEntityType ?? undefined,
      metadata: record.metadata as Record<string, unknown>,
      createdAt: record.createdAt,
    };
  }
}
