package server

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/tidbcloud/account/central/utils"

	"github.com/tidbcloud/account/internel/controllers/openapi"

	"github.com/tidbcloud/account/idl/pbgen/proto/account"

	pkg_http "github.com/tidbcloud/account/pkg/grpc/http"
	accounthandler "github.com/tidbcloud/account/thirdparty/account"
	"github.com/tidbcloud/pkgv2/auth/kong"
	"github.com/tidbcloud/tiinf/errs"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
)

type GRPCAuthType int

const (
	GRPCAuthTypeDumb GRPCAuthType = iota
	GRPCAuthTypeAuth0
	GRPCAuthTypeOpenAPI
)

func AuthFuncDumb(ctx context.Context) (context.Context, error) {
	return ctx, nil
}

func AuthFuncOpenAPI(ctx context.Context) (context.Context, error) {
	publicKey, err := getOpenAPIPublicKey(ctx)
	if err != nil {
		tilog.Info(ctx, "Failed to get OpenAPI public key", zap.Error(err))
		return nil, errs.NewUnauthorized(err.Error(), err)
	}

	tilog.Info(ctx, "AuthFuncOpenAPI", zap.String("publicKey", publicKey))

	req := &account.GetApiKeyByAccessKeyReq{
		AccessKey: publicKey,
	}
	rsp, err := accounthandler.GetHandler().GetApiKeyByAccessKey(ctx, req)
	tilog.Info(ctx, "AuthFuncOpenAPI GetApiKeyByPublicKey", zap.Any("rsp", rsp), zap.Any("err", err))

	if err != nil {
		tilog.Info(ctx, "Failed to call account-provider-svc GetApiKeyByPublicKey API", zap.String("publicKey", publicKey), zap.Error(err))
		return nil, utils.ConvertErr2GrpcErr(errs.NewUnauthorized("Failed to call account-provider-svc GetApiKeyByPublicKey API", err))
	}
	if rsp.ApiKey == nil {
		tilog.Info(ctx, "call account-provider-svc GetApiKeyByPublicKey API, return ApiKey nil", zap.String("publicKey", publicKey), zap.Error(err))
		return nil, utils.ConvertErr2GrpcErr(errs.NewUnauthorized("call account-provider-svc GetApiKeyByPublicKey API, return ApiKey nil", err))
	}
	newCtx := context.WithValue(ctx, openapi.OpenAPIAccessKey, rsp)

	return newCtx, nil
}

func getOpenAPIPublicKey(ctx context.Context) (string, error) {
	//authType := pkg_http.FirstHeader(ctx, "X-Auth-Type")
	//if authType != string(kong.AuthTypeOpenAPI) {
	//	return "", fmt.Errorf("Unexpected auth type: %s", authType)
	//}

	authContent := pkg_http.FirstHeader(ctx, "X-Auth-Content")
	result := new(kong.OpenAPIAuthResult)
	err := json.Unmarshal([]byte(authContent), result)
	if err != nil {
		return "", fmt.Errorf("Failed to unmarshal auth content: %s, error: %s", authContent, err)
	}
	publicKey := result.PublicKey
	if publicKey == "" {
		return "", fmt.Errorf("Failed to retrieve public_key: auth content: %s", authContent)
	}
	return publicKey, nil
}
