package pg

import (
	"context"
	"fmt"

	"github.com/Masterminds/squirrel"
	"go.sour.is/pkg/lg"
	"go.sour.is/pkg/mercury"
)

type grouper interface {
	GetGroups() []string
}

// GetRules get list of rules
func (p *postgresHandler) GetRules(ctx context.Context, user mercury.Ident) (lis mercury.Rules, err error) {
	ctx, span := lg.Span(ctx)
	defer span.End()

	var ids []string
	ids = append(ids, "U-"+user.GetIdentity())
	switch u := user.(type) {
	case grouper:
		for _, g := range u.GetGroups() {
			ids = append(ids, "G-"+g)
		}
	}
	if groups, err := p.getGroups(ctx, user.GetIdentity()); err != nil {
		for _, g := range groups {
			ids = append(ids, "G-"+g)
		}
	}

	query := squirrel.Select("role", "type", "match").
		From("mercury_rules_vw").
		Where(squirrel.Eq{"id": ids}).
		PlaceholderFormat(squirrel.Dollar)
	rows, err := query.
		RunWith(p.db).
		QueryContext(ctx)

	if err != nil {
		span.RecordError(err)
		return nil, err
	}

	defer rows.Close()
	for rows.Next() {
		var s mercury.Rule
		err = rows.Scan(&s.Role, &s.Type, &s.Match)
		if err != nil {
			span.RecordError(err)
			return nil, err
		}
		lis = append(lis, s)
	}
	err = rows.Err()
	span.RecordError(err)

	span.AddEvent(fmt.Sprint("read rules ", len(lis)))
	return lis, err
}

// getGroups get list of groups
func (pgm *postgresHandler) getGroups(ctx context.Context, user string) (lis []string, err error) {
	ctx, span := lg.Span(ctx)
	defer span.End()

	rows, err := squirrel.Select("group_id").
		From("mercury_groups_vw").
		Where(squirrel.Eq{"user_id": user}).
		PlaceholderFormat(squirrel.Dollar).
		RunWith(pgm.db).
		QueryContext(ctx)

	if err != nil {
		return nil, err
	}

	defer rows.Close()
	for rows.Next() {
		var s string
		err = rows.Scan(&s)
		if err != nil {
			return nil, err
		}
		lis = append(lis, s)
	}

	return lis, rows.Err()
}
