import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import {
  BackupShare,
  BackupShareStatus,
  BackupShareProps,
  BackupShareRepository,
} from '../../../domain';
import { BackupShare as PrismaBackupShare } from '@prisma/client';

@Injectable()
export class BackupShareRepositoryImpl implements BackupShareRepository {
  constructor(private readonly prisma: PrismaService) {}

  async save(share: BackupShare): Promise<BackupShare> {
    const props = share.toProps();

    if (props.shareId === null) {
      // Create new
      const created = await this.prisma.backupShare.create({
        data: {
          userId: props.userId,
          accountSequence: props.accountSequence,
          publicKey: props.publicKey,
          partyIndex: props.partyIndex,
          threshold: props.threshold,
          totalParties: props.totalParties,
          encryptedShareData: props.encryptedShareData,
          encryptionKeyId: props.encryptionKeyId,
          status: props.status,
          accessCount: props.accessCount,
          lastAccessedAt: props.lastAccessedAt,
          revokedAt: props.revokedAt,
        },
      });
      return this.toDomain(created);
    } else {
      // Update existing
      const updated = await this.prisma.backupShare.update({
        where: { shareId: props.shareId },
        data: {
          encryptedShareData: props.encryptedShareData,
          encryptionKeyId: props.encryptionKeyId,
          status: props.status,
          accessCount: props.accessCount,
          lastAccessedAt: props.lastAccessedAt,
          revokedAt: props.revokedAt,
        },
      });
      return this.toDomain(updated);
    }
  }

  async findById(shareId: bigint): Promise<BackupShare | null> {
    const record = await this.prisma.backupShare.findUnique({
      where: { shareId },
    });
    return record ? this.toDomain(record) : null;
  }

  async findByUserId(userId: bigint): Promise<BackupShare | null> {
    const record = await this.prisma.backupShare.findUnique({
      where: { userId },
    });
    return record ? this.toDomain(record) : null;
  }

  async findByPublicKey(publicKey: string): Promise<BackupShare | null> {
    const record = await this.prisma.backupShare.findUnique({
      where: { publicKey },
    });
    return record ? this.toDomain(record) : null;
  }

  async findByUserIdAndPublicKey(
    userId: bigint,
    publicKey: string,
  ): Promise<BackupShare | null> {
    const record = await this.prisma.backupShare.findFirst({
      where: {
        userId,
        publicKey,
      },
    });
    return record ? this.toDomain(record) : null;
  }

  async findByAccountSequence(
    accountSequence: string,
  ): Promise<BackupShare | null> {
    const record = await this.prisma.backupShare.findUnique({
      where: { accountSequence },
    });
    return record ? this.toDomain(record) : null;
  }

  async delete(shareId: bigint): Promise<void> {
    await this.prisma.backupShare.delete({
      where: { shareId },
    });
  }

  private toDomain(record: PrismaBackupShare): BackupShare {
    const props: BackupShareProps = {
      shareId: record.shareId,
      userId: record.userId,
      accountSequence: record.accountSequence,
      publicKey: record.publicKey,
      partyIndex: record.partyIndex,
      threshold: record.threshold,
      totalParties: record.totalParties,
      encryptedShareData: record.encryptedShareData,
      encryptionKeyId: record.encryptionKeyId,
      status: record.status as BackupShareStatus,
      accessCount: record.accessCount,
      lastAccessedAt: record.lastAccessedAt,
      createdAt: record.createdAt,
      updatedAt: record.updatedAt,
      revokedAt: record.revokedAt,
    };
    return BackupShare.reconstitute(props);
  }
}
