/**
 * PartyShare Factory
 *
 * Factory for creating PartyShare aggregate instances.
 * Encapsulates complex creation logic and ensures valid aggregates.
 */

import { PartyShare } from '../../entities/party-share.entity';
import {
  ShareId,
  PartyId,
  SessionId,
  ShareData,
  PublicKey,
  Threshold,
} from '../../value-objects';
import { PartyShareType, PartyShareStatus } from '../../enums';

export interface CreatePartyShareParams {
  partyId: string;
  sessionId: string;
  shareType: PartyShareType;
  encryptedShareData: {
    data: string;
    iv: string;
    authTag: string;
  };
  publicKeyHex: string;
  thresholdN: number;
  thresholdT: number;
}

export interface ReconstructPartyShareParams {
  id: string;
  partyId: string;
  sessionId: string;
  shareType: PartyShareType;
  shareDataJson: string;
  publicKeyHex: string;
  thresholdN: number;
  thresholdT: number;
  status: PartyShareStatus;
  createdAt: Date;
  updatedAt: Date;
  lastUsedAt?: Date;
}

export class PartyShareFactory {
  /**
   * Create a new PartyShare aggregate from raw input
   */
  static create(params: CreatePartyShareParams): PartyShare {
    const partyId = PartyId.create(params.partyId);
    const sessionId = SessionId.create(params.sessionId);
    const shareData = ShareData.fromJSON(params.encryptedShareData);
    const publicKey = PublicKey.fromHex(params.publicKeyHex);
    const threshold = Threshold.create(params.thresholdN, params.thresholdT);

    return PartyShare.create({
      partyId,
      sessionId,
      shareType: params.shareType,
      shareData,
      publicKey,
      threshold,
    });
  }

  /**
   * Reconstruct a PartyShare aggregate from persistence data
   */
  static reconstruct(params: ReconstructPartyShareParams): PartyShare {
    const id = ShareId.create(params.id);
    const partyId = PartyId.create(params.partyId);
    const sessionId = SessionId.create(params.sessionId);
    const shareData = ShareData.fromJSON(JSON.parse(params.shareDataJson));
    const publicKey = PublicKey.fromHex(params.publicKeyHex);
    const threshold = Threshold.create(params.thresholdN, params.thresholdT);

    return PartyShare.reconstruct({
      id,
      partyId,
      sessionId,
      shareType: params.shareType,
      shareData,
      publicKey,
      threshold,
      status: params.status,
      createdAt: params.createdAt,
      updatedAt: params.updatedAt,
      lastUsedAt: params.lastUsedAt,
    });
  }

  /**
   * Create a PartyShare for wallet key generation
   */
  static createWalletShare(
    partyId: string,
    sessionId: string,
    encryptedShareData: { data: string; iv: string; authTag: string },
    publicKeyHex: string,
    threshold: { n: number; t: number },
  ): PartyShare {
    return this.create({
      partyId,
      sessionId,
      shareType: PartyShareType.WALLET,
      encryptedShareData,
      publicKeyHex,
      thresholdN: threshold.n,
      thresholdT: threshold.t,
    });
  }

  /**
   * Create a PartyShare for admin multi-sig
   */
  static createAdminShare(
    partyId: string,
    sessionId: string,
    encryptedShareData: { data: string; iv: string; authTag: string },
    publicKeyHex: string,
    threshold: { n: number; t: number },
  ): PartyShare {
    return this.create({
      partyId,
      sessionId,
      shareType: PartyShareType.ADMIN,
      encryptedShareData,
      publicKeyHex,
      thresholdN: threshold.n,
      thresholdT: threshold.t,
    });
  }

  /**
   * Create a PartyShare for recovery purposes
   */
  static createRecoveryShare(
    partyId: string,
    sessionId: string,
    encryptedShareData: { data: string; iv: string; authTag: string },
    publicKeyHex: string,
    threshold: { n: number; t: number },
  ): PartyShare {
    return this.create({
      partyId,
      sessionId,
      shareType: PartyShareType.RECOVERY,
      encryptedShareData,
      publicKeyHex,
      thresholdN: threshold.n,
      thresholdT: threshold.t,
    });
  }
}
