package sqlparser

import (
	"fmt"
	"io/fs"

	"go.uber.org/multierr"
	"golang.org/x/sync/errgroup"
)

type ParsedSQL struct {
	UseTx    bool
	Up, Down []string
}

func ParseAllFromFS(fsys fs.FS, filename string, debug bool) (*ParsedSQL, error) {
	parsedSQL := new(ParsedSQL)
	// TODO(mf): parse is called twice, once for up and once for down. This is inefficient. It
	// should be possible to parse both directions in one pass. Also, UseTx is set once (but
	// returned twice), which is unnecessary and potentially error-prone if the two calls to
	// parseSQL disagree based on direction.
	var g errgroup.Group
	g.Go(func() error {
		up, useTx, err := parse(fsys, filename, DirectionUp, debug)
		if err != nil {
			return err
		}
		parsedSQL.Up = up
		parsedSQL.UseTx = useTx
		return nil
	})
	g.Go(func() error {
		down, _, err := parse(fsys, filename, DirectionDown, debug)
		if err != nil {
			return err
		}
		parsedSQL.Down = down
		return nil
	})
	if err := g.Wait(); err != nil {
		return nil, err
	}
	return parsedSQL, nil
}

func parse(fsys fs.FS, filename string, direction Direction, debug bool) (_ []string, _ bool, retErr error) {
	r, err := fsys.Open(filename)
	if err != nil {
		return nil, false, err
	}
	defer func() {
		retErr = multierr.Append(retErr, r.Close())
	}()
	stmts, useTx, err := ParseSQLMigration(r, direction, debug)
	if err != nil {
		return nil, false, fmt.Errorf("failed to parse %s: %w", filename, err)
	}
	return stmts, useTx, nil
}