import { Inject, Injectable, Logger } from '@nestjs/common';
import { StoreBackupShareCommand } from './store-backup-share.command';
import { BackupShare, BACKUP_SHARE_REPOSITORY } from '../../../domain';
import type { BackupShareRepository } from '../../../domain';
import { AesEncryptionService } from '../../../infrastructure/crypto/aes-encryption.service';
import { AuditLogRepository } from '../../../infrastructure/persistence/repositories/audit-log.repository';
import { ApplicationError } from '../../errors/application.error';

export interface StoreBackupShareResult {
  shareId: string;
}

@Injectable()
export class StoreBackupShareHandler {
  private readonly logger = new Logger(StoreBackupShareHandler.name);

  constructor(
    @Inject(BACKUP_SHARE_REPOSITORY)
    private readonly repository: BackupShareRepository,
    private readonly encryptionService: AesEncryptionService,
    private readonly auditLogRepository: AuditLogRepository,
  ) {}

  async execute(command: StoreBackupShareCommand): Promise<StoreBackupShareResult> {
    this.logger.log(`Storing backup share for user: ${command.userId}`);

    const userId = BigInt(command.userId);

    // Check if share already exists for this user
    const existing = await this.repository.findByUserId(userId);
    if (existing) {
      throw new ApplicationError(
        'Backup share already exists for this user',
        'SHARE_ALREADY_EXISTS',
      );
    }

    // Check if share already exists for this public key
    const existingByPubKey = await this.repository.findByPublicKey(command.publicKey);
    if (existingByPubKey) {
      throw new ApplicationError(
        'Backup share already exists for this public key',
        'SHARE_ALREADY_EXISTS',
      );
    }

    // Double encryption - the data is already encrypted by identity-service,
    // we encrypt it again for defense in depth
    const { encrypted, keyId } = await this.encryptionService.encrypt(
      command.encryptedShareData,
    );

    // Create domain entity
    const share = BackupShare.create({
      userId,
      accountSequence: command.accountSequence,
      publicKey: command.publicKey,
      encryptedShareData: encrypted,
      encryptionKeyId: keyId,
      threshold: command.threshold,
      totalParties: command.totalParties,
    });

    // Save to repository
    const saved = await this.repository.save(share);

    // Log audit
    await this.auditLogRepository.log({
      shareId: saved.shareId!,
      userId,
      action: 'STORE',
      sourceService: command.sourceService,
      sourceIp: command.sourceIp,
      success: true,
    });

    this.logger.log(`Backup share stored successfully: shareId=${saved.shareId}`);

    return {
      shareId: saved.shareId!.toString(),
    };
  }
}
