package store

import (
	"context"
	"fmt"
	"time"

	"go.mongodb.org/mongo-driver/v2/bson"
	"go.mongodb.org/mongo-driver/v2/mongo"

	"bountyboard/internal/ulid"
)

// PoolEntry is a developer-pool membership row (§4.3).
type PoolEntry struct {
	ID           string    `bson:"_id" json:"id"`
	ConsultantID string    `bson:"consultantId" json:"consultantId"`
	DeveloperID  string    `bson:"developerId" json:"developerId"`
	AddedAt      time.Time `bson:"addedAt" json:"addedAt"`
}

func (s *Store) AddToPool(ctx context.Context, consultantID, developerID string) error {
	_, err := s.DB.Collection("pools").InsertOne(ctx, PoolEntry{
		ID: ulid.New(), ConsultantID: consultantID, DeveloperID: developerID,
		AddedAt: time.Now().UTC(),
	})
	if err != nil {
		if mongo.IsDuplicateKeyError(err) {
			return ErrDuplicate
		}
		return fmt.Errorf("add to pool: %w", err)
	}
	return nil
}

func (s *Store) RemoveFromPool(ctx context.Context, consultantID, developerID string) error {
	res, err := s.DB.Collection("pools").DeleteOne(ctx,
		bson.M{"consultantId": consultantID, "developerId": developerID})
	if err != nil {
		return fmt.Errorf("remove from pool: %w", err)
	}
	if res.DeletedCount == 0 {
		return ErrNotFound
	}
	return nil
}

// PoolDeveloperIDs lists developers in one consultant's pool.
func (s *Store) PoolDeveloperIDs(ctx context.Context, consultantID string) ([]string, error) {
	return s.poolSide(ctx, bson.M{"consultantId": consultantID}, "developerId")
}

// PoolConsultantIDs lists consultants who selected the developer — drives
// the developer's bounty-board visibility (§3).
func (s *Store) PoolConsultantIDs(ctx context.Context, developerID string) ([]string, error) {
	return s.poolSide(ctx, bson.M{"developerId": developerID}, "consultantId")
}

func (s *Store) poolSide(ctx context.Context, filter bson.M, field string) ([]string, error) {
	cur, err := s.DB.Collection("pools").Find(ctx, filter)
	if err != nil {
		return nil, fmt.Errorf("list pool: %w", err)
	}
	var rows []PoolEntry
	if err := cur.All(ctx, &rows); err != nil {
		return nil, fmt.Errorf("decode pool: %w", err)
	}
	out := make([]string, 0, len(rows))
	for _, r := range rows {
		if field == "developerId" {
			out = append(out, r.DeveloperID)
		} else {
			out = append(out, r.ConsultantID)
		}
	}
	return out, nil
}
