package main

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

	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"

	"github.com/tidbcloud/tiinf/sdk/auth"

	"github.com/gin-gonic/gin"
)

// access call: curl -H 'Authorization:12345' 'http://localhost:8080/test'

func Example_Use_GinGetIdentityInfo() {
	eng := gin.Default()
	// you need init account client first, the account client is singleton
	auth.InitAccountClientByEndpoint("account-provider-grpc:10000", 0)

	eng.Use(
		auth.GinGetIdentityInfoInterceptor(&auth.IdentityAuthOption{
			EnableLog: true,
		}),
		auth.GinPermissionCheckInterceptor(&auth.PermissionCheckerCommonParam{
			IdentityF:               auth.GinGetIdentityFunc,
			PathPattern2ResourceMap: pathPattern2ResourceMap,
			PathWhitelist:           pathWhitelist,
			HttpReqCheckRetHandleF:  myPermissionCheckResultHandleFunc,
		}),
	)

	eng.GET("/:test", ginBizLogic)
	eng.GET("/api/v1/:test", ginBizLogic)
	eng.GET("/api/v1/orgs/:org_id/projects", ginBizLogic)
	eng.GET("/openapi/orgs/:org_id/projects", ginOpenAPILogic)
	eng.Run("127.0.0.1:8080")
}

func Example_Use_GinPermissionCheckInterceptor() {
	eng := gin.Default()
	// you need init account client first, the account client is singleton
	auth.InitAccountClientByEndpoint("account-provider-grpc:10000", 0)
	eng.Use(
		auth.GinPermissionCheckInterceptor(&auth.PermissionCheckerCommonParam{
			IdentityF:               mockGinGetIdentityFunc,
			PathPattern2ResourceMap: pathPattern2ResourceMap,
			PathWhitelist:           pathWhitelist,
			//HttpReqCheckRetHandleF:  myPermissionCheckResultHandleFunc,
		}),
	)

	eng.GET("/:test", ginBizLogic)
	eng.GET("/api/v1/orgs/:org_id/projects", ginBizLogic)
	eng.Run("127.0.0.1:8081")
}

func mockGinGetIdentityFunc(ctx context.Context, _ *auth.AccessParam) (*auth.IdentityRet, error) {
	return &auth.IdentityRet{
		IdentityType:  auth.AccessIdentityTypeUserID,
		IdentityValue: fmt.Sprintf("%d", 1001),
	}, nil
}

func ginOpenAPILogic(c *gin.Context) {
	authInfo, err := auth.GetIdentityInfoFromGinContext(c)
	if err != nil {
		log.Println("get auth Info failed %v", err)
	}
	log.Println("### example gin ###, receive req: %s authInfo: %v", c.Request.RequestURI, authInfo)
	projects, err := auth.ListProjectsFromApiKeyRsp(c.Request.Context(), authInfo.ApiKeyRsp)
	if err != nil {
		log.Println("ListProjectsFromApiKeyRsp failed %v", err)
	}
	log.Println("projects list is %v", projects)
}

func ginBizLogic(c *gin.Context) {
	authInfo, err := auth.GetIdentityInfoFromGinContext(c)
	if err != nil {
		log.Println("get auth Info failed %v", err)
	}
	log.Println("### example gin ###, receive req: %s authInfo: %v", c.Request.RequestURI, authInfo)
}

var pathPattern2ResourceMap = map[string]string{
	"/api/v1/orgs/(\\d+)/poc-applications":      "/orgs/{org_id}/owner",
	"/api/v1/orgs/(\\d+)/projects/(\\d+)/users": "/orgs/{org_id}/projects/{project_id}/list",
	"/api/v1/orgs/verification-email":           "/orgs/verification-email",
	"get,post, create:/:test":                   "/test/owner",
	"/test34":                                   "/test/owner",
	"/api/v1/orgs/(\\d+)/projects/(\\d+)/get":   "orgs/{org_id}/projects/{project_id}/get",
	"get:/api/v1/orgs/(\\d+)/projects":          "orgs/{org_id}/projects/list",
	"post:/api/v1/orgs/(\\d+)/projects":         "orgs/{org_id}/projects/create",
	"get:/openapi/orgs/(\\d+)/projects":         "account/openapi/orgs/{org_id}/list_projects",
}

var pathWhitelist = []string{
	"/health_check",
	"/ping",
	"/test12",
}

func myPermissionCheckResultHandleFunc(w http.ResponseWriter, r *http.Request, result *auth.AccessResult, err error) (continueRun bool) {
	tilog.Info(r.Context(), "access check result", zap.Any("result", result), zap.Any("err", err))
	if err != nil {
		w.WriteHeader(http.StatusForbidden)
		_, _ = w.Write([]byte(fmt.Sprintf("my Access denied: %s", err.Error())))
		return false

	}
	if result.Code != auth.AccessRetRelease {
		w.WriteHeader(http.StatusForbidden)
		_, _ = w.Write([]byte(fmt.Sprintf("my Access denied: %s", result.Msg)))
		return false
	}
	return true
}
