// command ooporthelper implements the Port Filtering test helper
package main

import (
	"context"
	"flag"
	"net"
	"sync"
	"time"

	"github.com/apex/log"
	"github.com/ooni/probe-cli/v3/internal/engine/experiment/portfiltering"
	"github.com/ooni/probe-cli/v3/internal/runtimex"
)

var (
	srvCtx      context.Context
	srvCancel   context.CancelFunc
	srvWg       = new(sync.WaitGroup)
	srvTestChan = make(chan string, len(TestPorts)) // buffered channel for testing
	srvTest     bool
)

func init() {
	srvCtx, srvCancel = context.WithCancel(context.Background())
}

func shutdown(ctx context.Context, l net.Listener) {
	<-ctx.Done()
	l.Close()
}

// TODO(DecFox): Add the ability of an echo service to generate some traffic
func handleConnection(ctx context.Context, conn net.Conn) {
	defer conn.Close()
	ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
	defer cancel()
	<-ctx.Done()
}

func listenTCP(ctx context.Context, port string) {
	defer srvWg.Done()
	address := net.JoinHostPort("127.0.0.1", port)
	listener, err := net.Listen("tcp", address)
	runtimex.PanicOnError(err, "net.Listen failed")
	go shutdown(ctx, listener)
	srvTestChan <- port // send to channel to imply server will start listening on port
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Infof("listener unable to accept connections on port: %s", port)
			return
		}
		go handleConnection(ctx, conn)
	}
}

func main() {
	logmap := map[bool]log.Level{
		true:  log.DebugLevel,
		false: log.InfoLevel,
	}
	debug := flag.Bool("debug", false, "Toggle debug mode")
	flag.Parse()
	log.SetLevel(logmap[*debug])
	defer srvCancel()
	ports := portfiltering.Ports
	if srvTest {
		ports = TestPorts
	}
	for _, port := range ports {
		srvWg.Add(1)
		ctx, cancel := context.WithCancel(srvCtx)
		defer cancel()
		go listenTCP(ctx, port)
	}
	<-srvCtx.Done()
	srvWg.Wait() // wait for listeners on all ports to close
}
