package api

import (
	"encoding/base64"
	"encoding/json"
	"eta/eta_mini_ht_api/common/component/cache"
	"eta/eta_mini_ht_api/common/component/config"
	logger "eta/eta_mini_ht_api/common/component/log"
	"eta/eta_mini_ht_api/common/contants"
	"eta/eta_mini_ht_api/common/exception"
	"eta/eta_mini_ht_api/common/utils/auth"
	"eta/eta_mini_ht_api/common/utils/client"
	"eta/eta_mini_ht_api/common/utils/redis"
	"fmt"
	"io"
	"sync"
	"time"
)

const (
	clientSuitInfoUrl = "/wt/front/api/open/api/getClientSuitInfo"
	accessTokenUrl    = "/api/openapi/authless/token"
)

var (
	htFacadeOnce sync.Once
	htFacade     *HTApi
)

type HTApi struct {
	htConfig *config.HTBizConfig
	// HTTP请求客户端
	client     *client.HttpClient
	redisUtils *cache.RedisCache
}

func GetInstance() *HTApi {
	htFacadeOnce.Do(func() {
		htFacade = &HTApi{
			htConfig:   config.GetConfig(contants.HT).(*config.HTBizConfig),
			client:     client.DefaultClient(),
			redisUtils: cache.GetInstance()}
	})
	return htFacade
}

type ClientSuitInfoReq struct {
	ClientName string `json:"client_name"`
	IdKind     int    `json:"id_kind"`
	IdNo       string `json:"id_no"`
}

type CustomerRiskReq struct {
	MobileTel  string `json:"mobile_tel"`
	ClientName string `json:"client_name"`
	IdKind     int    `json:"id_kind"`
	IdNo       string `json:"id_no"`
	CreateTime string `json:"create_time"`
	LoginType  string `json:"login_type"`
}

func (f *HTApi) EnCodeData(req CustomerRiskReq) (token string, err error) {
	publicKey, err := auth.ParsePublicKey(f.htConfig.GetWebhookPublicKey())
	if err != nil {
		logger.Error("解析公钥失败:%v", err)
		err = exception.New(exception.SysError)
		return
	}
	str, err := json.Marshal(req)
	if err != nil {
		logger.Error("json序列化失败:%v", err)
		err = exception.New(exception.SysError)
		return
	}
	rsa, err := auth.EncryptWithRSA(publicKey, str)
	if err != nil {
		logger.Error("公钥加密失败:%v", err)
		err = exception.New(exception.SysError)
		return
	}
	token = base64.StdEncoding.EncodeToString(rsa)
	return
}

type EncodeReq struct {
	Param string `json:"param"`
}

func (f *HTApi) getToken() (token string, err error) {
	accessToken := redis.GenerateCAPAccessTokenKey()
	token = f.redisUtils.GetString(accessToken)
	var tokenInfo TokenInfo
	if token == "" {
		tokenInfo, err = f.GetAccessToken()
		if err != nil {
			logger.Error("获取token失败%v", err)
			return
		}
		var parseErr error
		expireTime, parseErr := time.Parse(time.DateTime, tokenInfo.ExpiresAt)
		if parseErr != nil {
			logger.Error("解析过期时间失败:%v", parseErr)
			err = parseErr
			return
		}
		duration := expireTime.Sub(time.Now()).Seconds()
		token = tokenInfo.AccessToken
		_ = f.redisUtils.SetString(accessToken, tokenInfo.AccessToken, int(duration)-5)
	}
	return
}
func (f *HTApi) GetCustomerRiskLevelInfo(req ClientSuitInfoReq) (info CustomerAccountInfo, err error) {
	url := f.htConfig.GetAccountApiUrl() + clientSuitInfoUrl
	token, err := f.getToken()
	if err != nil {
		return
	}
	publicKey, err := auth.ParsePublicKey(f.htConfig.GetWebhookPublicKey())
	if err != nil {
		logger.Error("解析公钥失败:%v", err)
	}
	reqStr, err := json.Marshal(req)
	encodeData, _ := auth.EncryptWithRSA(publicKey, reqStr)
	resp, err := f.client.PostWithAuth(url, EncodeReq{
		Param: base64.StdEncoding.EncodeToString(encodeData),
	}, token)
	if err != nil {
		logger.Error("调用CAP customerRiskInfo接口失败:[%v]", err)
		return
	}
	defer func(Body io.ReadCloser) {
		closeErr := Body.Close()
		if closeErr != nil {
			logger.Error("关闭Response失败:%v", closeErr)
		}
	}(resp.Body)

	body, _ := io.ReadAll(resp.Body)
	return decodeResponse(body)
}

type AccessTokenReq struct {
	AppId     string `json:"app_id"`
	SecretKey string `json:"secret_key"`
}

func (f *HTApi) GetAccessToken() (token TokenInfo, err error) {
	url := f.htConfig.GetAccountApiUrl() + accessTokenUrl
	req := AccessTokenReq{
		AppId:     f.htConfig.GetAppId(),
		SecretKey: f.htConfig.GetSecretKey(),
	}
	resp, err := f.client.Post(url, req)
	if err != nil {
		logger.Error("调用CAP accessToken接口失败:[%v]", err)
		return
	}
	defer func(Body io.ReadCloser) {
		closeErr := Body.Close()
		if closeErr != nil {
			logger.Error("关闭Response失败:%v", closeErr)
		}
	}(resp.Body)
	body, _ := io.ReadAll(resp.Body)

	var tokenResp AccessTokenResp
	err = json.Unmarshal(body, &tokenResp)
	if err != nil {
		logger.Warn("[cap 接口调用]解析cap token接口应答失败:%v", err)
		err = exception.New(exception.GetCapTokenFailed)
		return
	}
	if tokenResp.Error.ErrorNo != "0" {
		logger.Warn("[cap 接口调用] 获取token失败:[code:%v, msg:%v, path:%v]", tokenResp.Error.ErrorNo, tokenResp.Error.ErrorInfo, tokenResp.Error.ErrorPathInfo)
		err = exception.NewWithException(exception.GetCapTokenFailed, tokenResp.Error.ErrorInfo)
		return
	}

	token = TokenInfo{
		AccessToken: tokenResp.Data.AccessToken,
		ExpiresAt:   tokenResp.Data.ExpiresAt,
	}
	return
}

type AccessTokenResp struct {
	Error Error           `json:"error"`
	Data  AccessTokenData `json:"data"`
}

type Error struct {
	ErrorNo       string `json:"error_no"`
	ErrorInfo     string `json:"error_info"`
	ErrorPathInfo string `json:"error_path_info"`
}

type AccessTokenData struct {
	AccessToken string `json:"accessToken"`
	ExpiresAt   string `json:"expiresAt"`
}

type TokenInfo struct {
	AccessToken string
	ExpiresAt   string
}

type CustomerRiskInfoResp struct {
	Error Error  `json:"error"`
	Data  string `json:"data"`
}

type SyncCustomerRiskLevelReq struct {
	CustInfo CustInfo `json:"custInfo"`
	RiskInfo RiskInfo `json:"riskInfo"`
}

type CustInfo struct {
	MobileTel   string `json:"mobile_tel"`
	ClientName  string `json:"client_name"`
	IdKind      string `json:"id_kind"`
	IdNo        string `json:"id_no"`
	IdBeginDate string `json:"id_begindate"`
	IdEndDate   string `json:"id_enddate"`
}

type RiskInfo struct {
	CorpBeginDate  string `json:"corp_begin_date"`
	CorpEndDate    string `json:"corp_end_date"`
	UserInvestTerm string `json:"user_invest_term"`
	UserInvestKind string `json:"user_invest_kind"`
	CorpRiskLevel  string `json:"corp_risk_level"`
}
type CustomerAccountInfo struct {
	CustInfo CustInfo `json:"custInfo"`
	RiskInfo RiskInfo `json:"riskInfo"`
}

func decodeResponse(resp []byte) (info CustomerAccountInfo, err error) {
	customerRiskInfoResp := new(CustomerRiskInfoResp)
	err = json.Unmarshal(resp, &customerRiskInfoResp)
	if err != nil {
		logger.Error("customerRiskInfoResp解析失败: %v", err)
		return
	}
	if err != nil {
		logger.Warn("[cap 接口调用]解析客户风险信息接口应答失败:%v", err)
		err = exception.New(exception.GetCapTokenFailed)
		return
	}
	if customerRiskInfoResp.Error.ErrorNo != "0" {
		logger.Warn("[cap 接口调用] 获取客户风险信息失败:[code:%v, msg:%v, path:%v]", customerRiskInfoResp.Error.ErrorNo, customerRiskInfoResp.Error.ErrorInfo, customerRiskInfoResp.Error.ErrorPathInfo)
		err = exception.NewWithException(exception.GetCustomerRiskInfoFailed, customerRiskInfoResp.Error.ErrorInfo)
		return
	}
	privateKey, err := auth.ParsePrivateKey(htFacade.htConfig.GetWebhookPrivateKey())
	if err != nil {
		logger.Error("解析私钥失败: %v", err)
		return
	}
	decodeData, err := auth.DecryptWithRSA(privateKey, customerRiskInfoResp.Data)
	if err != nil {
		logger.Error("解密请求体失败: %v", err)
		return
	}
	fmt.Printf("解密后的请求: %v", string(decodeData))
	err = json.Unmarshal(decodeData, &info)
	if err != nil {
		logger.Error("customerInfo解析失败: %v", err)
		return
	}
	return
}