package interceptor

import (
	"context"
	"testing"

	"github.com/smartystreets/goconvey/convey"
	"google.golang.org/grpc"

	globalserverlessv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/serverless/v1"
)

func TestProjectIdInterceptor(t *testing.T) {
	convey.Convey("TestProjectIdInterceptor", t, func() {
		// Create interceptor
		interceptor := ProjectIdInterceptor()

		convey.Convey("Test CreateRequest", func() {
			// Create test request
			req := &globalserverlessv1.ServerlessServiceCreateRequest{
				OriginalProjectId: 123,
			}

			// Mock handler
			handler := func(ctx context.Context, req any) (any, error) {
				// Verify ProjectId in request is set
				createReq, ok := req.(*globalserverlessv1.ServerlessServiceCreateRequest)
				convey.So(ok, convey.ShouldBeTrue)
				convey.So(createReq.ProjectId, convey.ShouldEqual, 123)

				// Create test response
				resp := &globalserverlessv1.ServerlessServiceCreateResponse{
					Cluster: &globalserverlessv1.ServerlessServiceCluster{
						ProjectId: 123,
					},
				}
				return resp, nil
			}

			// Call interceptor
			resp, err := interceptor(context.Background(), req, &grpc.UnaryServerInfo{}, handler)
			convey.So(err, convey.ShouldBeNil)

			// Verify response
			createResp, ok := resp.(*globalserverlessv1.ServerlessServiceCreateResponse)
			convey.So(ok, convey.ShouldBeTrue)
			convey.So(createResp.Cluster.ProjectId, convey.ShouldEqual, 0)
			convey.So(createResp.Cluster.OriginalProjectId, convey.ShouldEqual, 123)
		})

		convey.Convey("Test DeleteRequest", func() {
			// Create test request
			req := &globalserverlessv1.ServerlessServiceDeleteRequest{
				OriginalProjectId: 456,
			}

			// Mock handler
			handler := func(ctx context.Context, req any) (any, error) {
				// Verify ProjectId in request is set
				deleteReq, ok := req.(*globalserverlessv1.ServerlessServiceDeleteRequest)
				convey.So(ok, convey.ShouldBeTrue)
				convey.So(deleteReq.ProjectId, convey.ShouldEqual, 456)

				// Create test response
				resp := &globalserverlessv1.ServerlessServiceDeleteResponse{
					Cluster: &globalserverlessv1.ServerlessServiceCluster{
						ProjectId: 456,
					},
				}
				return resp, nil
			}

			// Call interceptor
			resp, err := interceptor(context.Background(), req, &grpc.UnaryServerInfo{}, handler)
			convey.So(err, convey.ShouldBeNil)

			// Verify response
			deleteResp, ok := resp.(*globalserverlessv1.ServerlessServiceDeleteResponse)
			convey.So(ok, convey.ShouldBeTrue)
			convey.So(deleteResp.Cluster.ProjectId, convey.ShouldEqual, 0)
			convey.So(deleteResp.Cluster.OriginalProjectId, convey.ShouldEqual, 456)
		})

		convey.Convey("Test UpdateRequest", func() {
			// Create test request
			req := &globalserverlessv1.ServerlessServiceUpdateRequest{
				Cluster: &globalserverlessv1.ServerlessServiceCluster{
					OriginalProjectId: 789,
				},
			}

			// Mock handler
			handler := func(ctx context.Context, req any) (any, error) {
				// Verify ProjectId in request is set
				updateReq, ok := req.(*globalserverlessv1.ServerlessServiceUpdateRequest)
				convey.So(ok, convey.ShouldBeTrue)
				convey.So(updateReq.Cluster.ProjectId, convey.ShouldEqual, 789)

				// Create test response
				resp := &globalserverlessv1.ServerlessServiceUpdateResponse{
					Cluster: &globalserverlessv1.ServerlessServiceCluster{
						ProjectId: 789,
					},
				}
				return resp, nil
			}

			// Call interceptor
			resp, err := interceptor(context.Background(), req, &grpc.UnaryServerInfo{}, handler)
			convey.So(err, convey.ShouldBeNil)

			// Verify response
			updateResp, ok := resp.(*globalserverlessv1.ServerlessServiceUpdateResponse)
			convey.So(ok, convey.ShouldBeTrue)
			convey.So(updateResp.Cluster.ProjectId, convey.ShouldEqual, 0)
			convey.So(updateResp.Cluster.OriginalProjectId, convey.ShouldEqual, 789)
		})

		convey.Convey("Test ListRequest", func() {
			// Create test request
			req := &globalserverlessv1.ServerlessServiceListRequest{
				Filter: &globalserverlessv1.ClusterFilter{
					OriginalProjectIds: []uint64{111, 222, 333},
				},
			}

			// Mock handler
			handler := func(ctx context.Context, req any) (any, error) {
				// Verify ProjectIds in request are set
				listReq, ok := req.(*globalserverlessv1.ServerlessServiceListRequest)
				convey.So(ok, convey.ShouldBeTrue)
				convey.So(listReq.Filter.ProjectIds, convey.ShouldResemble, []uint64{111, 222, 333})

				// Create test response
				resp := &globalserverlessv1.ServerlessServiceListResponse{
					Items: []*globalserverlessv1.ServerlessServiceCluster{
						{
							ProjectId: 111,
						},
						{
							ProjectId: 222,
						},
					},
				}
				return resp, nil
			}

			// Call interceptor
			resp, err := interceptor(context.Background(), req, &grpc.UnaryServerInfo{}, handler)
			convey.So(err, convey.ShouldBeNil)

			// Verify response
			listResp, ok := resp.(*globalserverlessv1.ServerlessServiceListResponse)
			convey.So(ok, convey.ShouldBeTrue)
			convey.So(len(listResp.Items), convey.ShouldEqual, 2)
			convey.So(listResp.Items[0].ProjectId, convey.ShouldEqual, 0)
			convey.So(listResp.Items[0].OriginalProjectId, convey.ShouldEqual, 111)
			convey.So(listResp.Items[1].ProjectId, convey.ShouldEqual, 0)
			convey.So(listResp.Items[1].OriginalProjectId, convey.ShouldEqual, 222)
		})

		convey.Convey("Test DeleteResponse", func() {
			// Create test request
			req := &globalserverlessv1.ServerlessServiceDeleteRequest{}

			// Mock handler
			handler := func(ctx context.Context, req any) (any, error) {
				// Create test response
				resp := &globalserverlessv1.ServerlessServiceDeleteResponse{
					Cluster: &globalserverlessv1.ServerlessServiceCluster{
						ProjectId: 999,
					},
				}
				return resp, nil
			}

			// Call interceptor
			resp, err := interceptor(context.Background(), req, &grpc.UnaryServerInfo{}, handler)
			convey.So(err, convey.ShouldBeNil)

			// Verify response
			deleteResp, ok := resp.(*globalserverlessv1.ServerlessServiceDeleteResponse)
			convey.So(ok, convey.ShouldBeTrue)
			convey.So(deleteResp.Cluster.ProjectId, convey.ShouldEqual, 0)
			convey.So(deleteResp.Cluster.OriginalProjectId, convey.ShouldEqual, 999)
		})

		convey.Convey("Test with nil req or resp", func() {
			// Test nil request
			var nilReq any
			// Mock handler
			handler := func(ctx context.Context, req any) (any, error) {
				return &globalserverlessv1.ServerlessServiceCreateResponse{}, nil
			}

			// Call interceptor
			resp, err := interceptor(context.Background(), nilReq, &grpc.UnaryServerInfo{}, handler)
			convey.So(err, convey.ShouldBeNil)
			convey.So(resp, convey.ShouldNotBeNil)
		})
	})
}
