package controlplane

import (
	"context"
	"fmt"
)

// readActivePackGenerationsForCatalog resolves every active pack through the
// immutable PackActivation -> PackGeneration authority chain. Callers must use
// the transaction that owns the surrounding Catalog compilation.
func readActivePackGenerationsForCatalog(
	ctx context.Context,
	tx PackGenerationAuthorityExecutor,
) ([]sourceBackedPackGeneration, error) {
	rows, err := tx.QueryContext(ctx, `SELECT PackName
FROM _System_PackActivation
WHERE COALESCE(IsDeleted, 0) = 0
ORDER BY BINARY PackName
FOR UPDATE`)
	if err != nil {
		return nil, err
	}
	var packNames []string
	for rows.Next() {
		var packName string
		if err := rows.Scan(&packName); err != nil {
			_ = rows.Close()
			return nil, err
		}
		packNames = append(packNames, packName)
	}
	if err := rows.Err(); err != nil {
		_ = rows.Close()
		return nil, err
	}
	if err := rows.Close(); err != nil {
		return nil, err
	}

	result := make([]sourceBackedPackGeneration, 0, len(packNames))
	for _, packName := range packNames {
		activation, found, err := readPackActivationForUpdate(ctx, tx, packName)
		if err != nil {
			return nil, err
		}
		if !found {
			return nil, fmt.Errorf(
				"%w: active pack %q activation disappeared during Catalog compilation",
				ErrPackGenerationConflict,
				packName,
			)
		}
		generation, err := verifyActivePackGeneration(ctx, tx, activation)
		if err != nil {
			return nil, fmt.Errorf(
				"active pack %q immutable generation authority: %w",
				packName,
				err,
			)
		}
		result = append(result, generation)
	}
	return result, nil
}
