package service import ( "context" "strings" "unicode/utf8" "veyra/services/api/internal/platform/apperror" "github.com/google/uuid" "veyra/services/api/internal/portfolio/domain" ) type Repository interface { Create(context.Context, domain.Account, *domain.CashEntry) (domain.AccountSummary, error) List(context.Context, string) ([]domain.AccountSummary, error) Get(context.Context, string, string) (domain.AccountSummary, error) } type AccountService struct{ repo Repository } func NewAccountService(repo Repository) *AccountService { return &AccountService{repo: repo} } func (s *AccountService) Create(ctx context.Context, userID, mode, name string, initialCash *string) (domain.AccountSummary, error) { if s.repo == nil { return domain.AccountSummary{}, apperror.ErrUnavailable } name = strings.TrimSpace(name) if name == "" || utf8.RuneCountInString(name) > 80 { return domain.AccountSummary{}, apperror.ErrInvalidInput } account := domain.Account{ID: uuid.NewString(), UserID: userID, Mode: mode, Name: name, Currency: "CNY", LedgerStatus: "INCOMPLETE"} var entry *domain.CashEntry switch mode { case "simulation": if initialCash == nil { return domain.AccountSummary{}, apperror.ErrInvalidInput } amount, err := domain.ParseMoney(*initialCash) if err != nil { return domain.AccountSummary{}, err } account.LedgerStatus = "COMPLETE" entry = &domain.CashEntry{ID: uuid.NewString(), AccountID: account.ID, EntryType: "INITIAL", AmountMinor: amount} case "manual_real": if initialCash != nil { return domain.AccountSummary{}, apperror.ErrInvalidInput } default: return domain.AccountSummary{}, apperror.ErrInvalidInput } return s.repo.Create(ctx, account, entry) } func (s *AccountService) List(ctx context.Context, userID string) ([]domain.AccountSummary, error) { if s.repo == nil { return nil, apperror.ErrUnavailable } return s.repo.List(ctx, userID) } func (s *AccountService) Get(ctx context.Context, userID, accountID string) (domain.AccountSummary, error) { if s.repo == nil { return domain.AccountSummary{}, apperror.ErrUnavailable } if _, err := uuid.Parse(accountID); err != nil { return domain.AccountSummary{}, apperror.ErrNotFound } return s.repo.Get(ctx, userID, accountID) }