package datastore

import "context"

// EmbeddingBackfillCandidate identifies one confirmed file revision whose
// non-empty semantic source is missing a current-generation vector.
type EmbeddingBackfillCandidate struct {
	InodeID  string
	Revision int64
}

// ListEmbeddingBackfillCandidates keyset-paginates one Store scope. Shared
// stores constrain both joined aliases by fs_id through the existing Scope.
func (s *Store) ListEmbeddingBackfillCandidates(ctx context.Context, afterInodeID string, generation uint64, limit int) ([]EmbeddingBackfillCandidate, error) {
	if limit <= 0 {
		return nil, nil
	}
	predicate := `i.status = 'CONFIRMED' AND i.inode_id > ? AND (
		(TRIM(COALESCE(s.content_text, '')) <> '' AND
		 (s.embedding IS NULL OR s.embedding_revision <> i.revision OR s.embedding_revision IS NULL OR
		  s.embedding_generation <> ? OR s.embedding_generation IS NULL)) OR
		(TRIM(COALESCE(s.description, '')) <> '' AND
		 (s.description_embedding IS NULL OR s.description_embedding_revision <> i.revision OR s.description_embedding_revision IS NULL OR
		  s.description_embedding_generation <> ? OR s.description_embedding_generation IS NULL))
	)`
	rows, err := s.db.QueryContext(ctx, `SELECT i.inode_id, i.revision
		FROM inodes i JOIN semantic s ON i.inode_id = s.inode_id
		WHERE `+scopeWhereAnd(s.scope, predicate, "i", "s")+`
		ORDER BY i.inode_id
		LIMIT ?`, scopeWhereArgs(s.scope, 2, afterInodeID, generation, generation, limit)...)
	if err != nil {
		return nil, err
	}
	defer func() { _ = rows.Close() }()

	out := make([]EmbeddingBackfillCandidate, 0, limit)
	for rows.Next() {
		var candidate EmbeddingBackfillCandidate
		if err := rows.Scan(&candidate.InodeID, &candidate.Revision); err != nil {
			return nil, err
		}
		out = append(out, candidate)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return out, nil
}
