package service import ( "context" "time" "gorm.io/gorm" "stream.api/internal/database/model" "stream.api/internal/dto" "stream.api/internal/repository" renderworkflow "stream.api/internal/workflow/render" ) type PaymentHistoryRow = repository.PaymentHistoryRow type CreateVideoInput = renderworkflow.CreateVideoInput type CreateVideoResult = renderworkflow.CreateVideoResult var ( ErrUserNotFound = renderworkflow.ErrUserNotFound ErrAdTemplateNotFound = renderworkflow.ErrAdTemplateNotFound ErrJobServiceUnavailable = renderworkflow.ErrJobServiceUnavailable ) type PaymentRepository interface { ListHistoryByUser(ctx context.Context, userID string, subscriptionKind string, walletTopupKind string, topupType string, limit int32, offset int) ([]PaymentHistoryRow, int64, error) ListForAdmin(ctx context.Context, userID string, status string, limit int32, offset int) ([]model.Payment, int64, error) CountAll(ctx context.Context) (int64, error) SumSuccessfulAmount(ctx context.Context) (float64, error) GetByIDAndUser(ctx context.Context, paymentID string, userID string) (*model.Payment, error) GetByID(ctx context.Context, paymentID string) (*model.Payment, error) GetStandaloneTopupByIDAndUser(ctx context.Context, id string, userID string, topupType string) (*model.WalletTransaction, error) GetSubscriptionByPaymentID(ctx context.Context, paymentID string) (*model.PlanSubscription, error) CountByPlanID(ctx context.Context, planID string) (int64, error) CreatePayment(ctx context.Context, payment *model.Payment) error Save(ctx context.Context, payment *model.Payment) error CreatePaymentTx(tx *gorm.DB, ctx context.Context, payment *model.Payment) error CreateWalletTransactionTx(tx *gorm.DB, ctx context.Context, txRecord *model.WalletTransaction) error CreatePlanSubscriptionTx(tx *gorm.DB, ctx context.Context, subscription *model.PlanSubscription) error UpdateUserPlanID(ctx context.Context, userID string, planID string) error UpdateUserPlanIDTx(tx *gorm.DB, ctx context.Context, userID string, planID string) error CreateNotificationTx(tx *gorm.DB, ctx context.Context, notification *model.Notification) error CreateWalletTopupAndNotification(ctx context.Context, userID string, transaction *model.WalletTransaction, notification *model.Notification) error ExecuteSubscriptionPayment(ctx context.Context, userID string, plan *model.Plan, termMonths int32, paymentMethod string, paymentRecord *model.Payment, invoiceID string, now time.Time, validateFunding func(currentWalletBalance float64) (float64, error)) (*model.PlanSubscription, float64, error) } type NotificationEventPublisher interface { PublishNotificationCreated(ctx context.Context, notification *model.Notification) error } type AccountRepository interface { DeleteUserAccount(ctx context.Context, userID string) error ClearUserData(ctx context.Context, userID string) error } type NotificationRepository interface { ListByUser(ctx context.Context, userID string) ([]model.Notification, error) MarkReadByIDAndUser(ctx context.Context, id string, userID string) (int64, error) MarkAllReadByUser(ctx context.Context, userID string) error DeleteByIDAndUser(ctx context.Context, id string, userID string) (int64, error) DeleteAllByUser(ctx context.Context, userID string) error } type DomainRepository interface { ListByUser(ctx context.Context, userID string) ([]model.Domain, error) CountByUserAndName(ctx context.Context, userID string, name string) (int64, error) Create(ctx context.Context, item *model.Domain) error DeleteByIDAndUser(ctx context.Context, id string, userID string) (int64, error) } type AdTemplateRepository interface { ListByUser(ctx context.Context, userID string) ([]model.AdTemplate, error) ListForAdmin(ctx context.Context, search string, userID string, limit int32, offset int) ([]model.AdTemplate, int64, error) CountAll(ctx context.Context) (int64, error) GetByID(ctx context.Context, id string) (*model.AdTemplate, error) GetByIDAndUser(ctx context.Context, id string, userID string) (*model.AdTemplate, error) ExistsByIDAndUser(ctx context.Context, id string, userID string) (bool, error) CreateWithDefault(ctx context.Context, userID string, item *model.AdTemplate) error SaveWithDefault(ctx context.Context, userID string, item *model.AdTemplate) error DeleteByIDAndUserAndClearVideos(ctx context.Context, id string, userID string) error DeleteByIDAndClearVideos(ctx context.Context, id string) error } type PopupAdRepository interface { ListByUser(ctx context.Context, userID string, limit int32, offset int) ([]model.PopupAd, int64, error) ListForAdmin(ctx context.Context, search string, userID string, limit int32, offset int) ([]model.PopupAd, int64, error) GetByID(ctx context.Context, id string) (*model.PopupAd, error) GetByIDAndUser(ctx context.Context, id string, userID string) (*model.PopupAd, error) GetActiveByUser(ctx context.Context, userID string) (*model.PopupAd, error) Create(ctx context.Context, item *model.PopupAd) error Save(ctx context.Context, item *model.PopupAd) error DeleteByIDAndUser(ctx context.Context, id string, userID string) (int64, error) DeleteByID(ctx context.Context, id string) (int64, error) } type PlayerConfigRepository interface { ListByUser(ctx context.Context, userID string) ([]model.PlayerConfig, error) ListForAdmin(ctx context.Context, search string, userID string, limit int32, offset int) ([]model.PlayerConfig, int64, error) CountByUser(ctx context.Context, userID string) (int64, error) CountByUserTx(tx *gorm.DB, ctx context.Context, userID string) (int64, error) Create(ctx context.Context, item *model.PlayerConfig) error CreateWithDefault(ctx context.Context, userID string, item *model.PlayerConfig) error CreateTx(tx *gorm.DB, ctx context.Context, item *model.PlayerConfig) error GetByID(ctx context.Context, id string) (*model.PlayerConfig, error) GetByIDAndUser(ctx context.Context, id string, userID string) (*model.PlayerConfig, error) GetByIDAndUserTx(tx *gorm.DB, ctx context.Context, id string, userID string) (*model.PlayerConfig, error) Save(ctx context.Context, item *model.PlayerConfig) error SaveWithDefault(ctx context.Context, userID string, item *model.PlayerConfig) error SaveTx(tx *gorm.DB, ctx context.Context, item *model.PlayerConfig) error DeleteByID(ctx context.Context, id string) (int64, error) DeleteByIDAndUser(ctx context.Context, id string, userID string) (int64, error) DeleteByIDAndUserTx(tx *gorm.DB, ctx context.Context, id string, userID string) (int64, error) UnsetDefaultForUser(ctx context.Context, userID string, excludeID string) error UnsetDefaultForUserTx(tx *gorm.DB, userID string, excludeID string) error CreateManaged(ctx context.Context, userID string, item *model.PlayerConfig, validate func(*model.User, int64) error) error DeleteManaged(ctx context.Context, userID string, id string, validate func(*model.User, int64) error) error UpdateManaged(ctx context.Context, userID string, id string, mutateAndValidate func(*model.PlayerConfig, *model.User, int64) error) (*model.PlayerConfig, error) } type VideoWorkflow interface { CreateVideo(ctx context.Context, input CreateVideoInput) (*CreateVideoResult, error) ListJobs(ctx context.Context, offset, limit int) (*dto.PaginatedJobs, error) ListJobsByAgent(ctx context.Context, agentID string, offset, limit int) (*dto.PaginatedJobs, error) ListJobsByCursor(ctx context.Context, agentID string, cursor string, pageSize int) (*dto.PaginatedJobs, error) GetJob(ctx context.Context, id string) (*model.Job, error) CreateJob(ctx context.Context, userID string, videoID string, name string, config []byte, priority int, timeLimit int64) (*model.Job, error) CancelJob(ctx context.Context, id string) error RetryJob(ctx context.Context, id string) (*model.Job, error) ListDLQ(ctx context.Context, offset, limit int) ([]*dto.DLQEntry, int64, error) GetDLQ(ctx context.Context, id string) (*dto.DLQEntry, error) RetryDLQ(ctx context.Context, id string) (*model.Job, error) RemoveDLQ(ctx context.Context, id string) error } type VideoRepository interface { ListByUser(ctx context.Context, userID string, search string, status string, offset int, limit int) ([]model.Video, int64, error) ListForAdmin(ctx context.Context, search string, userID string, status string, offset int, limit int) ([]model.Video, int64, error) CountAll(ctx context.Context) (int64, error) CountCreatedSince(ctx context.Context, since time.Time) (int64, error) IncrementViews(ctx context.Context, videoID string, userID string) error GetByID(ctx context.Context, videoID string) (*model.Video, error) GetByIDAndUser(ctx context.Context, videoID string, userID string) (*model.Video, error) UpdateByIDAndUser(ctx context.Context, videoID string, userID string, updates map[string]any) (int64, error) CountByUser(ctx context.Context, userID string) (int64, error) DeleteByIDAndUserWithStorageUpdate(ctx context.Context, videoID string, userID string, videoSize int64) error DeleteByIDWithStorageUpdate(ctx context.Context, videoID string, userID string, videoSize int64) error UpdateAdminVideo(ctx context.Context, video *model.Video, oldUserID string, oldSize int64, adTemplateID *string) error } type VideoWorkflowRepository interface { CreateVideoWithStorageAndAd(ctx context.Context, video *model.Video, userID string, adTemplateID *string) error GetUserByID(ctx context.Context, userID string) (*model.User, error) MarkVideoJobFailed(ctx context.Context, videoID string) error } type UserRepository interface { GetByEmail(ctx context.Context, email string) (*model.User, error) CountByEmail(ctx context.Context, email string) (int64, error) GetByID(ctx context.Context, userID string) (*model.User, error) LockByIDTx(tx *gorm.DB, ctx context.Context, userID string) (*model.User, error) ListForAdmin(ctx context.Context, search string, role string, limit int32, offset int) ([]model.User, int64, error) CountAll(ctx context.Context) (int64, error) CountCreatedSince(ctx context.Context, since time.Time) (int64, error) SumStorageUsed(ctx context.Context) (int64, error) GetEmailByID(ctx context.Context, userID string) (*string, error) GetReferralSummaryByID(ctx context.Context, userID string) (*model.User, error) CountByPlanID(ctx context.Context, planID string) (int64, error) Create(ctx context.Context, user *model.User) error UpdateFieldsByID(ctx context.Context, userID string, updates map[string]any) error UpdateFieldsByIDTx(tx *gorm.DB, ctx context.Context, userID string, updates map[string]any) error UpdatePassword(ctx context.Context, userID string, passwordHash string) error FindByReferralUsername(ctx context.Context, username string, limit int) ([]model.User, error) CountSubscriptionsByUser(ctx context.Context, userID string) (int64, error) } type UserPreferenceRepository interface { FindOrCreateByUserID(ctx context.Context, userID string) (*model.UserPreference, error) Save(ctx context.Context, pref *model.UserPreference) error } type BillingRepository interface { GetWalletBalance(ctx context.Context, userID string) (float64, error) GetWalletBalanceTx(tx *gorm.DB, ctx context.Context, userID string) (float64, error) GetLatestPlanSubscription(ctx context.Context, userID string) (*model.PlanSubscription, error) GetLatestPlanSubscriptionTx(tx *gorm.DB, ctx context.Context, userID string) (*model.PlanSubscription, error) CountActiveSubscriptions(ctx context.Context, now time.Time) (int64, error) } type PlanRepository interface { GetByID(ctx context.Context, planID string) (*model.Plan, error) ListActive(ctx context.Context) ([]model.Plan, error) ListAll(ctx context.Context) ([]model.Plan, error) Create(ctx context.Context, plan *model.Plan) error Save(ctx context.Context, plan *model.Plan) error CountPaymentsByPlan(ctx context.Context, planID string) (int64, error) CountSubscriptionsByPlan(ctx context.Context, planID string) (int64, error) SetActive(ctx context.Context, planID string, isActive bool) error DeleteByID(ctx context.Context, planID string) error } type JobRepository interface { Create(ctx context.Context, job *model.Job) error GetByID(ctx context.Context, id string) (*model.Job, error) GetLatestByVideoID(ctx context.Context, videoID string) (*model.Job, error) ListByCursor(ctx context.Context, agentID string, cursorTime time.Time, cursorID string, limit int) ([]*model.Job, bool, error) ListByOffset(ctx context.Context, agentID string, offset int, limit int) ([]*model.Job, int64, error) Save(ctx context.Context, job *model.Job) error UpdateVideoStatus(ctx context.Context, videoID string, statusValue string, processingStatus string) error AssignPendingJob(ctx context.Context, jobID string, agentID int64, now time.Time) (bool, error) MarkJobStatusIfCurrent(ctx context.Context, jobID string, fromStatuses []string, toStatus string, now time.Time, clearAgent bool) (bool, error) CancelJobIfActive(ctx context.Context, jobID string, now time.Time) (bool, error) RequeueJob(ctx context.Context, jobID string, retryCount int64, logs *string, now time.Time) (bool, error) MoveJobToFailure(ctx context.Context, jobID string, logs *string, now time.Time) (bool, error) UpdateProgressAndLogsIfRunning(ctx context.Context, jobID string, progress *float64, logs *string, now time.Time) (bool, error) } type AgentRuntime interface { ListAgentsWithStats() []*dto.AgentWithStats SendCommand(agentID string, cmd string) bool }