/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

// Package main implements a server for Greeter service.
package main

import (
	"context"
	"flag"
	"fmt"
	"net"
	"net/http"

	"github.com/gin-gonic/gin"
	grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
	"github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap"
	grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	pb "github.com/tidbcloud/tiinf/examples/tigrpc/helloworld/helloworld"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"github.com/tidbcloud/tiinf/monitor/titracing"
	"github.com/tidbcloud/tiinf/transport/http/tigin"
	tigrpc "github.com/tidbcloud/tiinf/transport/tigrpc/server"
	"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials/insecure"
)

var (
	port = flag.Int("port", 50051, "The server port")
)

// server is used to implement helloworld.GreeterServer.
type server struct {
	pb.UnimplementedGreeterServer
}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	tilog.Info(ctx, "Received message", zap.String("name", in.GetName()))
	panic(123)
	return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func exmaplePanicHandler(ctx context.Context, p interface{}) error {
	fmt.Println("my custom panic handler")
	return nil
}

func exampleMessageProducer(ctx context.Context, msg string, level zapcore.Level, code codes.Code, err error, duration zapcore.Field) {
	ctxzap.Extract(ctx).Check(level, msg).Write(
		zap.Error(err),
		zap.String("grpc.code", code.String()),
		duration,
		zap.String("hello", "world"),
	)
}

func main() {
	flag.Parse()

	// Init trace provider
	_, err := titracing.InitJaeger("exmaple")
	if err != nil {
		panic(err)
	}

	// Run metrics server
	go func() {
		http.Handle("/metrics", promhttp.Handler())
		err = http.ListenAndServe(":9090", nil)
		if err != nil {
			panic(err)
		}
	}()

	ctx := context.Background()
	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
	if err != nil {
		tilog.Fatal(ctx, "failed to listen", zap.Error(err))
	}
	s := tigrpc.NewServer(
		tigrpc.WithDefault(
			tigrpc.CustomizeRecoveryOption(
				grpc_recovery.WithRecoveryHandlerContext(exmaplePanicHandler),
			),
			tigrpc.CustomizeZapOption(
				grpc_zap.WithMessageProducer(exampleMessageProducer),
			),
		),
	)
	pb.RegisterGreeterServer(s, &server{})
	go func() {
		if err := s.Serve(lis); err != nil {
			tilog.Fatal(ctx, "failed to serve", zap.Error(err))
		}
	}()

	mux := runtime.NewServeMux()
	opts := []grpc.DialOption{
		grpc.WithTransportCredentials(insecure.NewCredentials()),
		grpc.WithChainUnaryInterceptor(
			otelgrpc.UnaryClientInterceptor(),
		),
	}
	pb.RegisterGreeterHandlerFromEndpoint(context.TODO(), mux, fmt.Sprintf(":%d", *port), opts)

	engine := tigin.Default()
	engine.Any("/*any", gin.WrapH(mux))
	engine.Run()
}
