// Command l4proxy is a runnable Layer-4 TCP proxy built on the l4
// package. It accepts connections, forwards them to a single origin with
// backpressure and half-close, optionally emits the PROXY protocol, and
// drains gracefully on SIGINT/SIGTERM.
//
//	go build -o /tmp/l4proxy ./cmd/l4proxy
//	/tmp/l4proxy -listen :8080 -origin 127.0.0.1:9000 -proxy-header
package main

import (
	"context"
	"flag"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"

	"gw01/l4"
)

func main() {
	listen := flag.String("listen", ":8080", "listen address")
	origin := flag.String("origin", "127.0.0.1:9000", "origin host:port")
	proxyHdr := flag.Bool("proxy-header", false, "emit PROXY protocol v1 to origin")
	drain := flag.Duration("drain", 25*time.Second, "graceful drain timeout")
	stats := flag.Duration("stats", 0, "if >0, print connection stats every interval")
	flag.Parse()

	p := &l4.Proxy{
		ListenAddr:   *listen,
		OriginAddr:   *origin,
		SendProxyV1:  *proxyHdr,
		DrainTimeout: *drain,
	}

	ctx, stop := signal.NotifyContext(context.Background(),
		syscall.SIGINT, syscall.SIGTERM)
	defer stop()

	if *stats > 0 {
		go sampleStats(ctx, p, *stats)
	}

	log.Printf("l4proxy listening on %s -> %s (proxy-header=%v, drain=%s)",
		*listen, *origin, *proxyHdr, *drain)
	if err := p.Run(ctx); err != nil {
		log.Printf("fatal: %v", err)
		os.Exit(1)
	}
	log.Printf("drained; bye")
}

func sampleStats(ctx context.Context, p *l4.Proxy, every time.Duration) {
	t := time.NewTicker(every)
	defer t.Stop()
	var lastAccepted int64
	for {
		select {
		case <-ctx.Done():
			return
		case <-t.C:
			a := p.Metrics.Accepted.Load()
			// connections.created/s — the churn signal (gw-04).
			log.Printf("accepted/s=%d active=%d total_accepted=%d dial_fails=%d up=%dB down=%dB",
				a-lastAccepted, p.Metrics.Active.Load(), a,
				p.Metrics.DialFails.Load(), p.Metrics.BytesUp.Load(), p.Metrics.BytesDown.Load())
			lastAccepted = a
		}
	}
}
