package captcha

import (
	"context"
	"net/http"
	"os"
	"strings"

	"bdrp-server/common/xerr"

	captcha20230305 "github.com/alibabacloud-go/captcha-20230305/client"
	openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
	"github.com/alibabacloud-go/tea/tea"
	"github.com/pkg/errors"
)

// contextKey 用于在 context 中存储 *http.Request，供 VerifyWithRequest 判断微信等环境
type contextKey struct{}

// HTTPRequestContextKey 为 context 中 http.Request 的 key，handler 可将 r 注入后传入 logic
var HTTPRequestContextKey = &contextKey{}

// isWeChatClient 根据 User-Agent 判断是否为微信内置浏览器/小程序环境（此类环境可不传 captchaVerifyParam，默认通过）
func isWeChatClient(r *http.Request) bool {
	if r == nil {
		return false
	}
	ua := strings.ToLower(r.Header.Get("User-Agent"))
	return strings.Contains(ua, "micromessenger") || strings.Contains(ua, "miniprogram")
}

type Config struct {
	AccessKeyID     string
	AccessKeySecret string
	EndpointURL     string
	SceneID         string
}

// VerifyWithRequest 在 Verify 基础上支持按请求头判断：微信/小程序环境下可不传 captchaVerifyParam，默认通过。
// 若 ctx 中带有 HTTPRequestContextKey 的 *http.Request，且 User-Agent 为微信环境，则不再校验 captchaVerifyParam。
func VerifyWithRequest(cfg Config, captchaVerifyParam string, ctx context.Context) error {
	if ctx != nil {
		if req, ok := ctx.Value(HTTPRequestContextKey).(*http.Request); ok && isWeChatClient(req) {
			return nil
		}
	}
	return Verify(cfg, captchaVerifyParam)
}

func Verify(cfg Config, captchaVerifyParam string) error {
	if os.Getenv("ENV") == "development" {
		return nil
	}

	if captchaVerifyParam == "" {
		return errors.Wrapf(xerr.NewErrMsg("图形验证码校验失败，captchaVerifyParam 不能为空"), "empty captchaVerifyParam")
	}

	clientCfg := &openapi.Config{
		AccessKeyId:     tea.String(cfg.AccessKeyID),
		AccessKeySecret: tea.String(cfg.AccessKeySecret),
	}
	clientCfg.Endpoint = tea.String(cfg.EndpointURL)
	client, err := captcha20230305.NewClient(clientCfg)
	if err != nil {
		return errors.Wrapf(xerr.NewErrMsg("图形验证码校验失败"), "new client error: %+v", err)
	}

	req := &captcha20230305.VerifyIntelligentCaptchaRequest{
		SceneId:            tea.String(cfg.SceneID),
		CaptchaVerifyParam: tea.String(captchaVerifyParam),
	}
	resp, err := client.VerifyIntelligentCaptcha(req)
	if err != nil {
		return errors.Wrapf(xerr.NewErrMsg("图形验证码校验失败"), "verify request error: %+v", err)
	}
	if tea.BoolValue(resp.Body.Result.VerifyResult) {
		return nil
	}
	return errors.Wrapf(xerr.NewErrMsg("图形验证码校验失败"), "verify result false")
}
