package service

import (
	"context"
	"fmt"
	"log/slog"
	"time"

	"github.com/owncord/server/telemetry"
)

// BlockService handles user block/unblock operations.
type BlockService struct {
	st Store
}

// NewBlockService creates a BlockService.
func NewBlockService(st Store) *BlockService {
	return &BlockService{st: st}
}

// BlockUser blocks a target user. Validates the target exists and
// prevents self-blocking.
func (s *BlockService) BlockUser(ctx context.Context, blockerID, targetID int64) error {
	ctx, span := telemetry.GlobalTracer("service/block").Start(ctx, "BlockService.BlockUser",
		telemetry.Int64("blocker_id", blockerID),
		telemetry.Int64("target_id", targetID),
	)
	start := time.Now()
	defer func() {
		telemetry.TimeSince(ctx, telemetry.NewAppMetrics().ServiceCallDurationSec, start,
			telemetry.String("method", "BlockUser"))
		span.End()
	}()

	if targetID <= 0 {
		return fmt.Errorf("%w: user_id must be positive", ErrBadRequest)
	}
	if blockerID == targetID {
		return fmt.Errorf("%w: cannot block yourself", ErrBadRequest)
	}

	target, err := s.st.GetUserByID(ctx, targetID)
	if err != nil || target == nil {
		return fmt.Errorf("%w: user not found", ErrNotFound)
	}

	if err := s.st.BlockUser(ctx, blockerID, targetID); err != nil {
		return fmt.Errorf("%w: failed to block user: %v", ErrInternal, err)
	}

	slog.Info("user blocked", "blocker_id", blockerID, "target_id", targetID)
	return nil
}

// UnblockUser removes a block on a target user.
func (s *BlockService) UnblockUser(ctx context.Context, blockerID, targetID int64) error {
	if targetID <= 0 {
		return fmt.Errorf("%w: user_id must be positive", ErrBadRequest)
	}
	if err := s.st.UnblockUser(ctx, blockerID, targetID); err != nil {
		return fmt.Errorf("%w: failed to unblock user: %v", ErrInternal, err)
	}
	slog.Info("user unblocked", "blocker_id", blockerID, "target_id", targetID)
	return nil
}

// ListBlocked returns all user IDs blocked by the given user.
func (s *BlockService) ListBlocked(ctx context.Context, blockerID int64) ([]int64, error) {
	ids, err := s.st.ListBlockedUsers(ctx, blockerID)
	if err != nil {
		return nil, fmt.Errorf("%w: failed to list blocked users: %v", ErrInternal, err)
	}
	if ids == nil {
		ids = []int64{}
	}
	return ids, nil
}
