package pushnotify

import (
	"context"

	"github.com/jackc/pgx/v5/pgxpool"
)

// Service stores per-device Expo push tokens and exposes the operations
// needed by both the HTTP handlers and the worker-side notifier.
type Service interface {
	// Register returns ErrInvalidToken / ErrInvalidPlatform on bad input.
	Register(ctx context.Context, humanID string, in RegisterInput) error
	// Unregister is scoped to humanID so a user can't delete another user's
	// token. Returns ErrNotFound if the token isn't owned by humanID.
	Unregister(ctx context.Context, humanID, token string) error
	// ListForHumans returns an empty slice when nothing matches.
	ListForHumans(ctx context.Context, humanIDs []string) ([]*PushToken, error)
	// DeleteByToken removes a token regardless of owner — used to prune after
	// Expo reports DeviceNotRegistered.
	DeleteByToken(ctx context.Context, token string) error
}

type RegisterInput struct {
	Token      string
	Platform   Platform
	AppVersion string
}

type serviceImpl struct {
	repo repository
}

func NewService(pool *pgxpool.Pool) Service {
	return &serviceImpl{repo: newRepository(pool)}
}

func (s *serviceImpl) Register(ctx context.Context, humanID string, in RegisterInput) error {
	if !in.Platform.Valid() {
		return ErrInvalidPlatform
	}
	if !IsValidExpoToken(in.Token) {
		return ErrInvalidToken
	}
	return s.repo.upsert(ctx, &PushToken{
		Token:      in.Token,
		HumanID:    humanID,
		Platform:   in.Platform,
		AppVersion: in.AppVersion,
	})
}

func (s *serviceImpl) Unregister(ctx context.Context, humanID, token string) error {
	if token == "" {
		return ErrInvalidToken
	}
	return s.repo.deleteForHuman(ctx, humanID, token)
}

func (s *serviceImpl) ListForHumans(ctx context.Context, humanIDs []string) ([]*PushToken, error) {
	return s.repo.listForHumans(ctx, humanIDs)
}

func (s *serviceImpl) DeleteByToken(ctx context.Context, token string) error {
	return s.repo.deleteByToken(ctx, token)
}
