package wechat

import (
	"context"

	"github.com/ArtisanCloud/PowerWeChat/v3/src/officialAccount"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"go.uber.org/zap"
)

// GetJSSDKConfig 获取 JSSDK 签名配置
// url 为当前页面完整 URL（含协议和路径，不含 # 及其后内容）
func (s *OfficialAccountService) GetJSSDKConfig(ctx context.Context, url string) (*JSSDKConfig, error) {
	if url == "" {
		return nil, errors.New(errors.CodeInvalidParam, "页面 URL 不能为空")
	}

	signMap, err := s.app.JSSDK.ConfigSignature(ctx, url, "", 0)
	if err != nil {
		s.logger.Error("获取 JSSDK 签名失败", zap.String("url", url), zap.Error(err))
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取 JSSDK 签名失败")
	}

	appID, _ := (*signMap)["appId"].(string)
	nonceStr, _ := (*signMap)["nonceStr"].(string)
	timestamp, _ := (*signMap)["timestamp"].(int64)
	signature, _ := (*signMap)["signature"].(string)

	s.logger.Debug("获取 JSSDK 签名配置成功",
		zap.String("app_id", appID),
		zap.String("url", url),
	)

	return &JSSDKConfig{
		AppID:     appID,
		Timestamp: timestamp,
		NonceStr:  nonceStr,
		Signature: signature,
	}, nil
}

// OfficialAccountService 微信公众号服务实现
type OfficialAccountService struct {
	app    *officialAccount.OfficialAccount
	logger *zap.Logger
}

// NewOfficialAccountService 创建微信公众号服务
func NewOfficialAccountService(app *officialAccount.OfficialAccount, logger *zap.Logger) *OfficialAccountService {
	return &OfficialAccountService{
		app:    app,
		logger: logger,
	}
}

// GetUserInfo 通过授权码获取用户基本信息（静默授权）
// 返回 OpenID 和 UnionID（如果有）
func (s *OfficialAccountService) GetUserInfo(ctx context.Context, code string) (openID, unionID string, err error) {
	if code == "" {
		return "", "", errors.New(errors.CodeInvalidParam, "授权码不能为空")
	}

	// 设置为静默授权模式（snsapi_base），只能获取 OpenID
	s.app.OAuth.SetScopes([]string{"snsapi_base"})

	user, err := s.app.OAuth.UserFromCode(code)
	if err != nil {
		s.logger.Error("微信 OAuth 授权失败",
			zap.String("code", code),
			zap.Error(err),
		)
		return "", "", errors.Wrap(errors.CodeWechatOAuthFailed, err)
	}

	if user == nil {
		s.logger.Error("微信 OAuth 返回空用户信息", zap.String("code", code))
		return "", "", errors.New(errors.CodeWechatOAuthFailed, "获取用户信息失败")
	}

	openID = user.GetOpenID()

	// 从原始数据中获取 UnionID
	raw, _ := user.GetRaw()
	if raw != nil {
		if uid, ok := (*raw)["unionid"].(string); ok {
			unionID = uid
		}
	}

	s.logger.Debug("微信 OAuth 授权成功",
		zap.String("open_id", openID),
		zap.String("union_id", unionID),
	)

	return openID, unionID, nil
}

// GetUserInfoDetailed 通过授权码获取用户详细信息（用户授权）
// 需要用户点击授权，可以获取昵称、头像等信息
func (s *OfficialAccountService) GetUserInfoDetailed(ctx context.Context, code string) (*UserInfo, error) {
	if code == "" {
		return nil, errors.New(errors.CodeInvalidParam, "授权码不能为空")
	}

	// 设置为用户信息授权模式（snsapi_userinfo）
	s.app.OAuth.SetScopes([]string{"snsapi_userinfo"})

	user, err := s.app.OAuth.UserFromCode(code)
	if err != nil {
		s.logger.Error("微信 OAuth 授权失败",
			zap.String("code", code),
			zap.Error(err),
		)
		return nil, errors.Wrap(errors.CodeWechatOAuthFailed, err)
	}

	if user == nil {
		s.logger.Error("微信 OAuth 返回空用户信息", zap.String("code", code))
		return nil, errors.New(errors.CodeWechatOAuthFailed, "获取用户信息失败")
	}

	raw, _ := user.GetRaw()

	userInfo := &UserInfo{
		OpenID: user.GetOpenID(),
	}

	if raw != nil {
		if uid, ok := (*raw)["unionid"].(string); ok {
			userInfo.UnionID = uid
		}
		if nickname, ok := (*raw)["nickname"].(string); ok {
			userInfo.Nickname = nickname
		}
		if headimgurl, ok := (*raw)["headimgurl"].(string); ok {
			userInfo.Avatar = headimgurl
		}
		if sex, ok := (*raw)["sex"].(float64); ok {
			userInfo.Sex = int(sex)
		}
		if province, ok := (*raw)["province"].(string); ok {
			userInfo.Province = province
		}
		if city, ok := (*raw)["city"].(string); ok {
			userInfo.City = city
		}
		if country, ok := (*raw)["country"].(string); ok {
			userInfo.Country = country
		}
	}

	s.logger.Debug("微信 OAuth 获取用户详细信息成功",
		zap.String("open_id", userInfo.OpenID),
		zap.String("nickname", userInfo.Nickname),
	)

	return userInfo, nil
}

// GetUserInfoByToken 通过 AccessToken 和 OpenID 获取用户详细信息
func (s *OfficialAccountService) GetUserInfoByToken(ctx context.Context, accessToken, openID string) (*UserInfo, error) {
	if accessToken == "" || openID == "" {
		return nil, errors.New(errors.CodeInvalidParam, "AccessToken 和 OpenID 不能为空")
	}

	user, err := s.app.OAuth.UserFromToken(accessToken, openID)
	if err != nil {
		s.logger.Error("通过 Token 获取微信用户信息失败",
			zap.String("open_id", openID),
			zap.Error(err),
		)
		return nil, errors.Wrap(errors.CodeWechatUserInfoFailed, err)
	}

	if user == nil {
		s.logger.Error("微信返回空用户信息", zap.String("open_id", openID))
		return nil, errors.New(errors.CodeWechatUserInfoFailed, "获取用户信息失败")
	}

	raw, _ := user.GetRaw()

	userInfo := &UserInfo{
		OpenID: user.GetOpenID(),
	}

	if raw != nil {
		if uid, ok := (*raw)["unionid"].(string); ok {
			userInfo.UnionID = uid
		}
		if nickname, ok := (*raw)["nickname"].(string); ok {
			userInfo.Nickname = nickname
		}
		if headimgurl, ok := (*raw)["headimgurl"].(string); ok {
			userInfo.Avatar = headimgurl
		}
		if sex, ok := (*raw)["sex"].(float64); ok {
			userInfo.Sex = int(sex)
		}
		if province, ok := (*raw)["province"].(string); ok {
			userInfo.Province = province
		}
		if city, ok := (*raw)["city"].(string); ok {
			userInfo.City = city
		}
		if country, ok := (*raw)["country"].(string); ok {
			userInfo.Country = country
		}
	}

	s.logger.Debug("通过 Token 获取微信用户详细信息成功",
		zap.String("open_id", userInfo.OpenID),
		zap.String("nickname", userInfo.Nickname),
	)

	return userInfo, nil
}
