import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import {
  CapabilityRepository,
  UserCapabilityRecord,
  CapabilityLogRecord,
} from '@/domain/repositories/capability.repository.interface';

@Injectable()
export class PrismaCapabilityRepository implements CapabilityRepository {
  constructor(private readonly prisma: PrismaService) {}

  async findByAccountSequence(accountSequence: string): Promise<UserCapabilityRecord[]> {
    return this.prisma.userCapability.findMany({
      where: { accountSequence },
    });
  }

  async upsert(data: {
    accountSequence: string;
    capability: string;
    enabled: boolean;
    reason?: string;
    disabledBy?: string;
    expiresAt?: Date;
  }): Promise<UserCapabilityRecord> {
    return this.prisma.userCapability.upsert({
      where: {
        accountSequence_capability: {
          accountSequence: data.accountSequence,
          capability: data.capability,
        },
      },
      create: {
        accountSequence: data.accountSequence,
        capability: data.capability,
        enabled: data.enabled,
        reason: data.reason,
        disabledBy: data.disabledBy,
        disabledAt: data.enabled ? null : new Date(),
        expiresAt: data.expiresAt,
      },
      update: {
        enabled: data.enabled,
        reason: data.reason,
        disabledBy: data.disabledBy,
        disabledAt: data.enabled ? null : new Date(),
        expiresAt: data.enabled ? null : data.expiresAt,
      },
    });
  }

  async upsertWithLog(
    upsertData: {
      accountSequence: string;
      capability: string;
      enabled: boolean;
      reason?: string;
      disabledBy?: string;
      expiresAt?: Date;
    },
    logData: {
      accountSequence: string;
      capability: string;
      action: string;
      reason?: string;
      operatorId?: string;
      previousValue: boolean;
      newValue: boolean;
      expiresAt?: Date;
    },
  ): Promise<UserCapabilityRecord> {
    return this.prisma.$transaction(async (tx) => {
      const record = await tx.userCapability.upsert({
        where: {
          accountSequence_capability: {
            accountSequence: upsertData.accountSequence,
            capability: upsertData.capability,
          },
        },
        create: {
          accountSequence: upsertData.accountSequence,
          capability: upsertData.capability,
          enabled: upsertData.enabled,
          reason: upsertData.reason,
          disabledBy: upsertData.disabledBy,
          disabledAt: upsertData.enabled ? null : new Date(),
          expiresAt: upsertData.expiresAt,
        },
        update: {
          enabled: upsertData.enabled,
          reason: upsertData.reason,
          disabledBy: upsertData.disabledBy,
          disabledAt: upsertData.enabled ? null : new Date(),
          expiresAt: upsertData.enabled ? null : upsertData.expiresAt,
        },
      });
      await tx.capabilityLog.create({ data: logData });
      return record;
    });
  }

  async findExpired(): Promise<UserCapabilityRecord[]> {
    return this.prisma.userCapability.findMany({
      where: {
        enabled: false,
        expiresAt: { not: null, lte: new Date() },
      },
    });
  }

  async createLog(data: {
    accountSequence: string;
    capability: string;
    action: string;
    reason?: string;
    operatorId?: string;
    previousValue: boolean;
    newValue: boolean;
    expiresAt?: Date;
  }): Promise<void> {
    await this.prisma.capabilityLog.create({ data });
  }

  async findLogsByAccountSequence(
    accountSequence: string,
    page: number,
    pageSize: number,
  ): Promise<{ data: CapabilityLogRecord[]; total: number }> {
    const [data, total] = await Promise.all([
      this.prisma.capabilityLog.findMany({
        where: { accountSequence },
        orderBy: { createdAt: 'desc' },
        skip: (page - 1) * pageSize,
        take: pageSize,
      }),
      this.prisma.capabilityLog.count({ where: { accountSequence } }),
    ]);
    return { data, total };
  }
}
