package main

import (
	"context"
	"errors"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/health"
	pb "google.golang.org/grpc/health/grpc_health_v1"
	"google.golang.org/grpc/reflection"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func main() {
	if err := run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
func run() error {
	token := os.Getenv("FIXTURE_TOKEN")
	if token == "" {
		return errors.New("FIXTURE_TOKEN is required")
	}
	httpLn, err := net.Listen("tcp", "127.0.0.1:18888")
	if err != nil {
		return err
	}
	defer httpLn.Close()
	grpcLn, err := net.Listen("tcp", "127.0.0.1:18889")
	if err != nil {
		return err
	}
	defer grpcLn.Close()
	mux := http.NewServeMux()
	mux.HandleFunc("/ready", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, token) })
	mux.HandleFunc("/ok", func(w http.ResponseWriter, r *http.Request) {
		timer := time.NewTimer(10 * time.Millisecond)
		defer timer.Stop()
		select {
		case <-r.Context().Done():
			return
		case <-timer.C:
			fmt.Fprint(w, "ok")
		}
	})
	mux.HandleFunc("/fail", func(w http.ResponseWriter, r *http.Request) { http.Error(w, "fixture failure", 503) })
	httpSrv := &http.Server{Handler: mux, ReadHeaderTimeout: time.Second}
	grpcSrv := grpc.NewServer()
	h := health.NewServer()
	h.SetServingStatus("", pb.HealthCheckResponse_SERVING)
	pb.RegisterHealthServer(grpcSrv, h)
	reflection.Register(grpcSrv)
	httpDone := make(chan error, 1)
	grpcDone := make(chan error, 1)
	go func() { httpDone <- httpSrv.Serve(httpLn) }()
	go func() { grpcDone <- grpcSrv.Serve(grpcLn) }()
	fmt.Println("fixtures: http 127.0.0.1:18888; grpc 127.0.0.1:18889; max lifetime 20s")
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
	defer stop()
	timer := time.NewTimer(20 * time.Second)
	defer timer.Stop()
	select {
	case <-ctx.Done():
	case <-timer.C:
	}
	clean, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	err = httpSrv.Shutdown(clean)
	if err != nil {
		_ = httpSrv.Close()
	}
	grpcSrv.Stop()
	he := <-httpDone
	ge := <-grpcDone
	if !errors.Is(he, http.ErrServerClosed) {
		return he
	}
	if ge != nil && !errors.Is(ge, grpc.ErrServerStopped) {
		return ge
	}
	return err
}
