import { WalletSessionStatus, ParticipantStatus } from '../enums/wallet-session-status.enum';

/**
 * 参与方信息
 */
export interface Participant {
  partyId: string;
  name: string;
  status: ParticipantStatus;
  joinedAt: Date;
}

/**
 * 阈值配置
 */
export interface ThresholdConfig {
  t: number; // 签名所需最少参与方数量
  n: number; // 总参与方数量
}

/**
 * 共管钱包会话实体
 */
export class CoManagedWalletSessionEntity {
  private constructor(
    private readonly _id: string,
    private readonly _walletName: string,
    private readonly _threshold: ThresholdConfig,
    private readonly _inviteCode: string,
    private _status: WalletSessionStatus,
    private _participants: Participant[],
    private _currentRound: number,
    private _totalRounds: number,
    private _publicKey: string | null,
    private _error: string | null,
    private readonly _createdAt: Date,
    private _updatedAt: Date,
    private readonly _createdBy: string,
  ) {}

  /**
   * 创建新会话
   */
  static create(params: {
    id: string;
    walletName: string;
    threshold: ThresholdConfig;
    inviteCode: string;
    createdBy: string;
    initiatorName: string;
    initiatorPartyId: string;
  }): CoManagedWalletSessionEntity {
    const now = new Date();
    const initialParticipant: Participant = {
      partyId: params.initiatorPartyId,
      name: params.initiatorName,
      status: ParticipantStatus.READY,
      joinedAt: now,
    };

    return new CoManagedWalletSessionEntity(
      params.id,
      params.walletName,
      params.threshold,
      params.inviteCode,
      WalletSessionStatus.WAITING,
      [initialParticipant],
      0,
      3, // 默认 3 轮
      null,
      null,
      now,
      now,
      params.createdBy,
    );
  }

  /**
   * 从持久化数据重建实体
   */
  static reconstitute(params: {
    id: string;
    walletName: string;
    threshold: ThresholdConfig;
    inviteCode: string;
    status: WalletSessionStatus;
    participants: Participant[];
    currentRound: number;
    totalRounds: number;
    publicKey: string | null;
    error: string | null;
    createdAt: Date;
    updatedAt: Date;
    createdBy: string;
  }): CoManagedWalletSessionEntity {
    return new CoManagedWalletSessionEntity(
      params.id,
      params.walletName,
      params.threshold,
      params.inviteCode,
      params.status,
      params.participants,
      params.currentRound,
      params.totalRounds,
      params.publicKey,
      params.error,
      params.createdAt,
      params.updatedAt,
      params.createdBy,
    );
  }

  // Getters
  get id(): string {
    return this._id;
  }

  get walletName(): string {
    return this._walletName;
  }

  get threshold(): ThresholdConfig {
    return { ...this._threshold };
  }

  get inviteCode(): string {
    return this._inviteCode;
  }

  get status(): WalletSessionStatus {
    return this._status;
  }

  get participants(): Participant[] {
    return [...this._participants];
  }

  get currentRound(): number {
    return this._currentRound;
  }

  get totalRounds(): number {
    return this._totalRounds;
  }

  get publicKey(): string | null {
    return this._publicKey;
  }

  get error(): string | null {
    return this._error;
  }

  get createdAt(): Date {
    return this._createdAt;
  }

  get updatedAt(): Date {
    return this._updatedAt;
  }

  get createdBy(): string {
    return this._createdBy;
  }

  /**
   * 检查是否可以添加新参与方
   */
  canAddParticipant(): boolean {
    return (
      this._status === WalletSessionStatus.WAITING &&
      this._participants.length < this._threshold.n
    );
  }

  /**
   * 添加参与方
   */
  addParticipant(partyId: string, name: string): void {
    if (!this.canAddParticipant()) {
      throw new Error('无法添加参与方');
    }

    if (this._participants.some((p) => p.partyId === partyId)) {
      throw new Error('参与方已存在');
    }

    this._participants.push({
      partyId,
      name,
      status: ParticipantStatus.READY,
      joinedAt: new Date(),
    });
    this._updatedAt = new Date();

    // 检查是否所有参与方都已加入
    if (this._participants.length === this._threshold.n) {
      this._status = WalletSessionStatus.READY;
    }
  }

  /**
   * 开始密钥生成
   */
  startKeygen(): void {
    if (this._status !== WalletSessionStatus.READY) {
      throw new Error('会话未就绪，无法开始密钥生成');
    }

    this._status = WalletSessionStatus.PROCESSING;
    this._currentRound = 1;
    this._participants = this._participants.map((p) => ({
      ...p,
      status: ParticipantStatus.PROCESSING,
    }));
    this._updatedAt = new Date();
  }

  /**
   * 更新轮次
   */
  updateRound(round: number): void {
    if (this._status !== WalletSessionStatus.PROCESSING) {
      throw new Error('会话不在处理中状态');
    }

    this._currentRound = round;
    this._updatedAt = new Date();
  }

  /**
   * 完成密钥生成
   */
  complete(publicKey: string): void {
    if (this._status !== WalletSessionStatus.PROCESSING) {
      throw new Error('会话不在处理中状态');
    }

    this._status = WalletSessionStatus.COMPLETED;
    this._publicKey = publicKey;
    this._participants = this._participants.map((p) => ({
      ...p,
      status: ParticipantStatus.COMPLETED,
    }));
    this._updatedAt = new Date();
  }

  /**
   * 标记失败
   */
  fail(error: string): void {
    this._status = WalletSessionStatus.FAILED;
    this._error = error;
    this._participants = this._participants.map((p) => ({
      ...p,
      status: ParticipantStatus.FAILED,
    }));
    this._updatedAt = new Date();
  }

  /**
   * 取消会话
   */
  cancel(): void {
    if (
      this._status === WalletSessionStatus.COMPLETED ||
      this._status === WalletSessionStatus.FAILED
    ) {
      throw new Error('无法取消已完成或已失败的会话');
    }

    this._status = WalletSessionStatus.CANCELLED;
    this._updatedAt = new Date();
  }
}

/**
 * 共管钱包实体 (创建成功后的记录)
 */
export class CoManagedWalletEntity {
  private constructor(
    private readonly _id: string,
    private readonly _sessionId: string,
    private readonly _name: string,
    private readonly _publicKey: string,
    private readonly _threshold: ThresholdConfig,
    private readonly _participants: Array<{ partyId: string; name: string }>,
    private readonly _createdAt: Date,
    private readonly _createdBy: string,
  ) {}

  static create(params: {
    id: string;
    sessionId: string;
    name: string;
    publicKey: string;
    threshold: ThresholdConfig;
    participants: Array<{ partyId: string; name: string }>;
    createdBy: string;
  }): CoManagedWalletEntity {
    return new CoManagedWalletEntity(
      params.id,
      params.sessionId,
      params.name,
      params.publicKey,
      params.threshold,
      params.participants,
      new Date(),
      params.createdBy,
    );
  }

  static reconstitute(params: {
    id: string;
    sessionId: string;
    name: string;
    publicKey: string;
    threshold: ThresholdConfig;
    participants: Array<{ partyId: string; name: string }>;
    createdAt: Date;
    createdBy: string;
  }): CoManagedWalletEntity {
    return new CoManagedWalletEntity(
      params.id,
      params.sessionId,
      params.name,
      params.publicKey,
      params.threshold,
      params.participants,
      params.createdAt,
      params.createdBy,
    );
  }

  // Getters
  get id(): string {
    return this._id;
  }

  get sessionId(): string {
    return this._sessionId;
  }

  get name(): string {
    return this._name;
  }

  get publicKey(): string {
    return this._publicKey;
  }

  get threshold(): ThresholdConfig {
    return { ...this._threshold };
  }

  get participants(): Array<{ partyId: string; name: string }> {
    return [...this._participants];
  }

  get createdAt(): Date {
    return this._createdAt;
  }

  get createdBy(): string {
    return this._createdBy;
  }
}
