package server

import (
	"context"
	"fmt"
	"strconv"

	usersvc "github.com/tidbcloud/account/internel/svc/user"

	"github.com/duke-git/lancet/v2/slice"
	"github.com/gin-gonic/gin"
	"github.com/pingcap/errors"
	"github.com/tidbcloud/account/commons/config"
	"github.com/tidbcloud/account/idl/pbgen/proto/account"
	"github.com/tidbcloud/tiinf/sdk/auth"
	"google.golang.org/grpc"
)

func UnaryServerAccessInterceptor() grpc.UnaryServerInterceptor {
	if config.IsLocalEnv() {
		pathWhitelist = slice.Concat(pathWhitelist, localPathWhitelist)

	}
	return auth.GrpcGatewayPermissionCheckUnaryServerInterceptor(&auth.PermissionCheckerCommonParam{
		IdentityF:               authGetIdentityFunc,
		PathPattern2ResourceMap: pathPatternResourceMap,
		PathWhitelist:           pathWhitelist,
		EnableLog:               true,
	})
}

func init() {
	auth.InitAccountClientByEndpoint(config.Global().GrpcConfig.AccountSvcAddr, 0)
}

func StreamServerAccessInterceptor() grpc.StreamServerInterceptor {
	if config.IsLocalEnv() {
		pathWhitelist = slice.Concat(pathWhitelist, localPathWhitelist)

	}
	return auth.GrpcGatewayPermissionCheckStreamServerInterceptor(&auth.PermissionCheckerCommonParam{
		IdentityF:               authGetIdentityFunc,
		PathPattern2ResourceMap: pathPatternResourceMap,
		PathWhitelist:           pathWhitelist,
		EnableLog:               true,
	})
}

func authGetIdentityFunc(ctx context.Context, _ *auth.AccessParam) (*auth.IdentityRet, error) {
	u, err := usersvc.GetUserFromContext(ctx)
	if err != nil {
		return nil, errors.New("get user from context error")
	}
	return &auth.IdentityRet{
		IdentityType:  auth.AccessIdentityTypeUserID,
		IdentityValue: fmt.Sprintf("%d", u.User.ID),
	}, nil
}

func LocalTestIdentity(c *gin.Context) {

	if config.IsLocalEnv() {

		orgIdStr := c.GetHeader("X-Test-Org-ID")
		orgId, _ := strconv.ParseUint(orgIdStr, 10, 64)
		userIdStr := c.GetHeader("X-Test-User-ID")
		userId, _ := strconv.ParseUint(userIdStr, 10, 64)
		apiKey := c.GetHeader("X-Test-ApiKey")
		authIdentityTypeStr := c.GetHeader("X-Test-AuthIdentityType")
		var authnIdentityType auth.AuthnIdentityType
		if authIdentityTypeStr == string(auth.AuthnIdentityTypeAccessToken) {

			authnIdentityType = auth.AuthnIdentityTypeAccessToken
		} else if authIdentityTypeStr == string(auth.AuthnIdentityTypeApiKeyAK) {

			authnIdentityType = auth.AuthnIdentityTypeApiKeyAK
		}

		authInfo := &auth.AuthnIdentityInfo{
			IdentityType: authnIdentityType,
			ApiKeyRsp: &account.GetApiKeyByAccessKeyRsp{
				ApiKey:        &account.ApiKey{AccessKey: apiKey},
				ResourceInfos: []*account.ApiKeyResourceInfo{{ScopeType: "ORG", ResourceId: orgId}}},
			AccessTokenRsp: &account.GetIdentityByAccessTokenResp{AccessTokenIdentity: &account.AccessTokenIdentity{UserId: userId, OrgId: orgId}},
		}

		c.Set(auth.IdentityInfoKey, authInfo)
	}

}
