package admin import ( "context" "encoding/json" "strings" "github.com/google/uuid" "github.com/yuxingu/digital-psychology/apps/api/internal/repository" ) var ( ErrPlanNotFound = errString("plan not found") ErrInvalidPlanU = errString("invalid plan update") ) // ListMembershipPlans returns catalog. func (s *Service) ListMembershipPlans(ctx context.Context) ([]repository.MembershipPlanRow, error) { items, err := s.Repo.ListMembershipPlans(ctx) if err != nil { return nil, err } if items == nil { items = []repository.MembershipPlanRow{} } return items, nil } // GetMembershipPlan returns one plan. func (s *Service) GetMembershipPlan(ctx context.Context, code string) (*repository.MembershipPlanRow, error) { p, err := s.Repo.GetMembershipPlan(ctx, code) if err != nil { return nil, err } if p == nil { return nil, ErrPlanNotFound } return p, nil } // UpdateMembershipPlan updates mutable fields. func (s *Service) UpdateMembershipPlan( ctx context.Context, adminID uuid.UUID, code, title string, days, amount int, active bool, ) (*repository.MembershipPlanRow, error) { code = strings.TrimSpace(code) title = strings.TrimSpace(title) if title == "" || days <= 0 || amount < 0 { return nil, ErrInvalidPlanU } if _, err := s.GetMembershipPlan(ctx, code); err != nil { return nil, err } meta, _ := json.Marshal(map[string]any{ "title": title, "duration_days": days, "amount_cents": amount, "active": active, }) if err := s.Repo.UpdateMembershipPlanWithAudit(ctx, adminID, code, title, days, amount, active, meta); err != nil { return nil, err } return s.GetMembershipPlan(ctx, code) } // PlanDurationDays resolves grant length from catalog with hardcoded fallback. func (s *Service) PlanDurationDays(ctx context.Context, plan string) (int, error) { p, err := s.Repo.GetMembershipPlan(ctx, plan) if err != nil { return 0, err } if p != nil && p.Active && p.DurationDays > 0 { return p.DurationDays, nil } return planDaysFallback(plan) } func planDaysFallback(plan string) (int, error) { switch plan { case "month": return 31, nil case "quarter": return 92, nil case "year": return 366, nil default: return 0, ErrInvalidPlan } }