package use_cases import ( "context" "github.com/rwadurian/mpc-system/services/account/application/ports" "github.com/rwadurian/mpc-system/services/account/domain/entities" "github.com/rwadurian/mpc-system/services/account/domain/repositories" "github.com/rwadurian/mpc-system/services/account/domain/services" "github.com/rwadurian/mpc-system/services/account/domain/value_objects" ) // CreateAccountUseCase handles account creation type CreateAccountUseCase struct { accountRepo repositories.AccountRepository shareRepo repositories.AccountShareRepository domainService *services.AccountDomainService eventPublisher ports.EventPublisher } // NewCreateAccountUseCase creates a new CreateAccountUseCase func NewCreateAccountUseCase( accountRepo repositories.AccountRepository, shareRepo repositories.AccountShareRepository, domainService *services.AccountDomainService, eventPublisher ports.EventPublisher, ) *CreateAccountUseCase { return &CreateAccountUseCase{ accountRepo: accountRepo, shareRepo: shareRepo, domainService: domainService, eventPublisher: eventPublisher, } } // Execute creates a new account func (uc *CreateAccountUseCase) Execute(ctx context.Context, input ports.CreateAccountInput) (*ports.CreateAccountOutput, error) { // Convert shares input shares := make([]services.ShareInfo, len(input.Shares)) for i, s := range input.Shares { shares[i] = services.ShareInfo{ ShareType: s.ShareType, PartyID: s.PartyID, PartyIndex: s.PartyIndex, DeviceType: s.DeviceType, DeviceID: s.DeviceID, } } // Create account using domain service account, err := uc.domainService.CreateAccount(ctx, services.CreateAccountInput{ Username: input.Username, Email: input.Email, Phone: input.Phone, PublicKey: input.PublicKey, KeygenSessionID: input.KeygenSessionID, ThresholdN: input.ThresholdN, ThresholdT: input.ThresholdT, Shares: shares, }) if err != nil { return nil, err } // Get created shares accountShares, err := uc.shareRepo.GetByAccountID(ctx, account.ID) if err != nil { return nil, err } // Publish event if uc.eventPublisher != nil { _ = uc.eventPublisher.Publish(ctx, ports.AccountEvent{ Type: ports.EventTypeAccountCreated, AccountID: account.ID.String(), Data: map[string]interface{}{ "username": account.Username, "email": account.Email, "thresholdN": account.ThresholdN, "thresholdT": account.ThresholdT, }, }) } return &ports.CreateAccountOutput{ Account: account, Shares: accountShares, }, nil } // GetAccountUseCase handles getting account information type GetAccountUseCase struct { accountRepo repositories.AccountRepository shareRepo repositories.AccountShareRepository } // NewGetAccountUseCase creates a new GetAccountUseCase func NewGetAccountUseCase( accountRepo repositories.AccountRepository, shareRepo repositories.AccountShareRepository, ) *GetAccountUseCase { return &GetAccountUseCase{ accountRepo: accountRepo, shareRepo: shareRepo, } } // Execute gets account information func (uc *GetAccountUseCase) Execute(ctx context.Context, input ports.GetAccountInput) (*ports.GetAccountOutput, error) { var account *entities.Account var err error switch { case input.AccountID != nil: account, err = uc.accountRepo.GetByID(ctx, *input.AccountID) case input.Username != nil: account, err = uc.accountRepo.GetByUsername(ctx, *input.Username) case input.Email != nil: account, err = uc.accountRepo.GetByEmail(ctx, *input.Email) default: return nil, entities.ErrAccountNotFound } if err != nil { return nil, err } // Get shares shares, err := uc.shareRepo.GetActiveByAccountID(ctx, account.ID) if err != nil { return nil, err } return &ports.GetAccountOutput{ Account: account, Shares: shares, }, nil } // UpdateAccountUseCase handles account updates type UpdateAccountUseCase struct { accountRepo repositories.AccountRepository eventPublisher ports.EventPublisher } // NewUpdateAccountUseCase creates a new UpdateAccountUseCase func NewUpdateAccountUseCase( accountRepo repositories.AccountRepository, eventPublisher ports.EventPublisher, ) *UpdateAccountUseCase { return &UpdateAccountUseCase{ accountRepo: accountRepo, eventPublisher: eventPublisher, } } // Execute updates an account func (uc *UpdateAccountUseCase) Execute(ctx context.Context, input ports.UpdateAccountInput) (*ports.UpdateAccountOutput, error) { account, err := uc.accountRepo.GetByID(ctx, input.AccountID) if err != nil { return nil, err } if input.Phone != nil { account.SetPhone(*input.Phone) } // Handle signing parties update if input.ClearSigningParties { account.ClearSigningParties() } else if len(input.SigningParties) > 0 { if err := account.SetSigningParties(input.SigningParties); err != nil { return nil, err } } if err := uc.accountRepo.Update(ctx, account); err != nil { return nil, err } // Publish event if uc.eventPublisher != nil { _ = uc.eventPublisher.Publish(ctx, ports.AccountEvent{ Type: ports.EventTypeAccountUpdated, AccountID: account.ID.String(), Data: map[string]interface{}{}, }) } return &ports.UpdateAccountOutput{ Account: account, }, nil } // DeactivateShareUseCase handles share deactivation type DeactivateShareUseCase struct { accountRepo repositories.AccountRepository shareRepo repositories.AccountShareRepository eventPublisher ports.EventPublisher } // NewDeactivateShareUseCase creates a new DeactivateShareUseCase func NewDeactivateShareUseCase( accountRepo repositories.AccountRepository, shareRepo repositories.AccountShareRepository, eventPublisher ports.EventPublisher, ) *DeactivateShareUseCase { return &DeactivateShareUseCase{ accountRepo: accountRepo, shareRepo: shareRepo, eventPublisher: eventPublisher, } } // Execute deactivates a share func (uc *DeactivateShareUseCase) Execute(ctx context.Context, input ports.DeactivateShareInput) error { // Verify account exists _, err := uc.accountRepo.GetByID(ctx, input.AccountID) if err != nil { return err } // Get share share, err := uc.shareRepo.GetByID(ctx, input.ShareID) if err != nil { return err } // Verify share belongs to account if !share.AccountID.Equals(input.AccountID) { return entities.ErrShareNotFound } // Deactivate share share.Deactivate() if err := uc.shareRepo.Update(ctx, share); err != nil { return err } // Publish event if uc.eventPublisher != nil { _ = uc.eventPublisher.Publish(ctx, ports.AccountEvent{ Type: ports.EventTypeShareDeactivated, AccountID: input.AccountID.String(), Data: map[string]interface{}{ "shareId": input.ShareID, "shareType": share.ShareType.String(), }, }) } return nil } // ListAccountsInput represents input for listing accounts type ListAccountsInput struct { Offset int Limit int } // ListAccountsOutput represents output from listing accounts type ListAccountsOutput struct { Accounts []*entities.Account Total int64 } // ListAccountsUseCase handles listing accounts type ListAccountsUseCase struct { accountRepo repositories.AccountRepository } // NewListAccountsUseCase creates a new ListAccountsUseCase func NewListAccountsUseCase(accountRepo repositories.AccountRepository) *ListAccountsUseCase { return &ListAccountsUseCase{ accountRepo: accountRepo, } } // Execute lists accounts with pagination func (uc *ListAccountsUseCase) Execute(ctx context.Context, input ListAccountsInput) (*ListAccountsOutput, error) { if input.Limit <= 0 { input.Limit = 20 } if input.Limit > 100 { input.Limit = 100 } accounts, err := uc.accountRepo.List(ctx, input.Offset, input.Limit) if err != nil { return nil, err } total, err := uc.accountRepo.Count(ctx) if err != nil { return nil, err } return &ListAccountsOutput{ Accounts: accounts, Total: total, }, nil } // GetAccountSharesUseCase handles getting account shares type GetAccountSharesUseCase struct { accountRepo repositories.AccountRepository shareRepo repositories.AccountShareRepository } // NewGetAccountSharesUseCase creates a new GetAccountSharesUseCase func NewGetAccountSharesUseCase( accountRepo repositories.AccountRepository, shareRepo repositories.AccountShareRepository, ) *GetAccountSharesUseCase { return &GetAccountSharesUseCase{ accountRepo: accountRepo, shareRepo: shareRepo, } } // GetAccountSharesOutput represents output from getting account shares type GetAccountSharesOutput struct { Shares []*entities.AccountShare } // Execute gets shares for an account func (uc *GetAccountSharesUseCase) Execute(ctx context.Context, accountID value_objects.AccountID) (*GetAccountSharesOutput, error) { // Verify account exists _, err := uc.accountRepo.GetByID(ctx, accountID) if err != nil { return nil, err } shares, err := uc.shareRepo.GetByAccountID(ctx, accountID) if err != nil { return nil, err } return &GetAccountSharesOutput{ Shares: shares, }, nil }