package stub

import (
	"fmt"
	"strings"
	"text/template"
)

// GeneratePermissiveStub generates Go source files for a permissive HTTP server
// that returns 200 OK with an empty JSON body for any request.
// cp9 doctor should flag services using permissive stubs.
func GeneratePermissiveStub(cfg *Config) (map[string]string, error) {
	httpPort := cfg.HTTPPort
	if httpPort == 0 {
		httpPort = DefaultHTTPPort
	}
	grpcPort := cfg.GRPCPort
	if grpcPort == 0 {
		grpcPort = DefaultGRPCPort
	}

	data := permissiveTemplateData{
		Service:  cfg.Service,
		HTTPPort: httpPort,
		GRPCPort: grpcPort,
	}

	var b strings.Builder
	if err := permissiveMainTmpl.Execute(&b, data); err != nil {
		return nil, fmt.Errorf("execute permissive template: %w", err)
	}

	return map[string]string{"main.go": b.String()}, nil
}

type permissiveTemplateData struct {
	Service  string
	HTTPPort int
	GRPCPort int
}

var permissiveMainTmpl = template.Must(template.New("permissive-main").Parse(`package main

import (
	"fmt"
	"io"
	"log"
	"net"
	"net/http"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"
)

// Permissive stub for {{.Service}}.
// Returns 200 OK with empty JSON for any HTTP request and zero-value protobuf
// messages for any unary gRPC request.
// WARNING: No API definition found — cp9 doctor will flag this.

func main() {
	mux := http.NewServeMux()

	mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		fmt.Fprint(w, ` + "`" + `{}` + "`" + `)
	})

	mux.HandleFunc("GET /healthz", func(w http.ResponseWriter, _ *http.Request) {
		w.WriteHeader(http.StatusOK)
		fmt.Fprint(w, ` + "`" + `{"status":"ok"}` + "`" + `)
	})

	httpAddr := fmt.Sprintf(":%d", {{.HTTPPort}})
	grpcAddr := fmt.Sprintf(":%d", {{.GRPCPort}})

	grpcServer := grpc.NewServer(grpc.UnknownServiceHandler(func(_ any, stream grpc.ServerStream) error {
		var req emptypb.Empty
		if err := stream.RecvMsg(&req); err != nil && err != io.EOF {
			return status.Errorf(codes.Internal, "decode: %v", err)
		}
		return stream.SendMsg(&emptypb.Empty{})
	}))

	lis, err := net.Listen("tcp", grpcAddr)
	if err != nil {
		log.Fatalf("failed to listen on %s: %v", grpcAddr, err)
	}

	errCh := make(chan error, 2)
	go func() {
		errCh <- http.ListenAndServe(httpAddr, mux)
	}()
	go func() {
		errCh <- grpcServer.Serve(lis)
	}()

	log.Printf("{{.Service}} permissive stub listening on http=%s grpc=%s (no API definition)", httpAddr, grpcAddr)
	if err := <-errCh; err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}
`))
