package wechat

import (
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"mini-chat/internal/code"
	"mini-chat/internal/pkg/core"
	"mini-chat/internal/pkg/httpclient"
	"mini-chat/internal/pkg/validation"
	"mini-chat/internal/repository/mysql/model"

	"github.com/DanPlayer/randomname"
)

type miniprogramLoginRequest struct {
	AppID  string `json:"app_id" binding:"required"`  // 小程序AppID
	JSCode string `json:"js_code" binding:"required"` // 登录时获取的code
}

type miniprogramLoginResponse struct {
	Success  bool   `json:"success"`
	Message  string `json:"message"`
	Token    string `json:"token"`             // 登录token
	UserID   string `json:"user_id"`           // 用户ID
	UserName string `json:"user_name"`         // 用户昵称
	Avatar   string `json:"user_avatar"`       // 用户头像
	OpenID   string `json:"openid,omitempty"`  // 用户唯一标识
	UnionID  string `json:"unionid,omitempty"` // 用户在开放平台的唯一标识符
}

// Code2SessionResponse 微信code2Session接口响应
type Code2SessionResponse struct {
	OpenID     string `json:"openid"`      // 用户唯一标识
	SessionKey string `json:"session_key"` // 会话密钥
	UnionID    string `json:"unionid"`     // 用户在开放平台的唯一标识符
	ErrCode    int    `json:"errcode"`     // 错误码
	ErrMsg     string `json:"errmsg"`      // 错误信息
}

// MiniprogramLogin 小程序登录
// @Summary 小程序登录
// @Description 通过AppID和code获取用户的openid，系统自动生成用户名和头像
// @Tags 微信
// @Accept json
// @Produce json
// @Param request body miniprogramLoginRequest true "请求参数"
// @Success 200 {object} miniprogramLoginResponse
// @Failure 400 {object} code.Failure
// @Failure 500 {object} code.Failure
// @Router /api/wechat/miniprogram/login [post]
func (h *handler) MiniprogramLogin() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(miniprogramLoginRequest)
		res := new(miniprogramLoginResponse)

		if err := ctx.ShouldBindJSON(req); err != nil {
			ctx.AbortWithError(core.Error(
				http.StatusBadRequest,
				code.ParamBindError,
				validation.Error(err),
			))
			return
		}

		// 根据AppID查询小程序信息获取AppSecret
		miniProgram, err := h.readDB.MiniProgram.WithContext(ctx.RequestContext()).
			Where(h.readDB.MiniProgram.AppID.Eq(req.AppID)).
			First()
		if err != nil {
			h.logger.Error(fmt.Sprintf("查询小程序信息失败: %s", err.Error()))
			ctx.AbortWithError(core.Error(
				http.StatusBadRequest,
				code.ServerError,
				"小程序不存在或查询失败",
			))
			return
		}

		// 调用微信code2Session接口
		openID, sessionKey, unionID, err := h.callCode2Session(ctx, req.AppID, miniProgram.AppSecret, req.JSCode)
		if err != nil {
			h.logger.Error(fmt.Sprintf("调用微信code2Session接口失败: %s", err.Error()))
			ctx.AbortWithError(core.Error(
				http.StatusInternalServerError,
				code.ServerError,
				err.Error(),
			))
			return
		}

		// 查询或创建用户
		user, err := h.getOrCreateUser(ctx, req.AppID, openID, unionID)
		if err != nil {
			h.logger.Error(fmt.Sprintf("获取或创建用户失败: %s", err.Error()))
			ctx.AbortWithError(core.Error(
				http.StatusInternalServerError,
				code.ServerError,
				"用户创建失败",
			))
			return
		}

		// 生成登录token
		token, err := h.generateToken(user.UserID, sessionKey)
		if err != nil {
			h.logger.Error(fmt.Sprintf("生成token失败: %s", err.Error()))
			ctx.AbortWithError(core.Error(
				http.StatusInternalServerError,
				code.ServerError,
				"token生成失败",
			))
			return
		}

		// 授权成功，主动发消息
		createData := new(model.AppMessageLog)
		createData.AppID = req.AppID
		createData.SenderID = "888888"
		createData.SenderName = "平台"
		createData.Content = `{"messages":"您好，欢迎开启专属体验之旅！"}`
		createData.ReceiverID = openID
		createData.MsgType = 1
		createData.SendTime = time.Now()
		createData.CreatedAt = time.Now()
		if err := h.writeDB.AppMessageLog.WithContext(ctx.RequestContext()).Create(createData); err != nil {
			h.logger.Error(fmt.Sprintf("授权成功，主动发消息失败: %s", err.Error()))
		}

		res.Success = true
		res.Message = "登录成功"
		res.Token = token
		res.UserID = user.UserID
		res.UserName = user.UserName
		res.Avatar = user.UserAvatar
		res.OpenID = openID
		res.UnionID = unionID

		ctx.Payload(res)
	}
}

// getOrCreateUser 获取或创建用户
func (h *handler) getOrCreateUser(ctx core.Context, appID, openID, unionID string) (*model.AppUser, error) {
	// 先查询用户是否存在（使用openID作为用户ID）
	user, err := h.readDB.AppUser.WithContext(ctx.RequestContext()).
		Where(h.readDB.AppUser.AppID.Eq(appID)).
		Where(h.readDB.AppUser.UserID.Eq(openID)).
		First()

	if err == nil {
		// 用户已存在，直接返回
		return user, nil
	}

	username := randomname.GenerateName()

	// 生成头像URL
	avatarURL, err := h.generateAvatar(openID)
	if err != nil {
		h.logger.Warn(fmt.Sprintf("生成头像失败: %s，使用默认头像", err.Error()))
		avatarURL = "/static/avatars/default.svg"
	}

	// 创建新用户
	newUser := &model.AppUser{
		AppID:      appID,
		UserID:     openID, // 使用openID作为用户ID
		UserName:   username,
		UserMobile: "", // 暂时为空
		UserAvatar: avatarURL,
		CreatedAt:  time.Now(),
	}

	err = h.writeDB.AppUser.WithContext(ctx.RequestContext()).Create(newUser)
	if err != nil {
		return nil, fmt.Errorf("创建用户失败: %v", err)
	}

	return newUser, nil
}

// generateAvatar 生成头像URL
func (h *handler) generateAvatar(seed string) (string, error) {
	// 使用dicebear API生成头像
	// 直接使用seed作为头像种子，确保每个用户有不同的头像
	avatarURL := fmt.Sprintf("https://api.dicebear.com/7.x/avataaars/svg?seed=%s", seed)
	fmt.Printf("生成头像URL: %s\n", avatarURL)
	return avatarURL, nil
}

// generateToken 生成登录token
func (h *handler) generateToken(userID, sessionKey string) (string, error) {
	// 生成32字节的随机token
	bytes := make([]byte, 32)
	if _, err := rand.Read(bytes); err != nil {
		return "", err
	}

	token := hex.EncodeToString(bytes)

	// TODO: 这里应该将token保存到缓存或数据库中，并设置过期时间
	// 可以结合sessionKey一起存储，用于后续的用户身份验证

	return token, nil
}

// callCode2Session 调用微信code2Session接口
func (h *handler) callCode2Session(ctx core.Context, appID, appSecret, jsCode string) (string, string, string, error) {
	// 构建请求URL
	url := "https://api.weixin.qq.com/sns/jscode2session"

	// 发送HTTP请求
	client := httpclient.GetHttpClientWithContext(ctx.RequestContext())
	resp, err := client.R().
		SetQueryParams(map[string]string{
			"appid":      appID,
			"secret":     appSecret,
			"js_code":    jsCode,
			"grant_type": "authorization_code",
		}).
		Get(url)

	if err != nil {
		return "", "", "", fmt.Errorf("HTTP请求失败: %v", err)
	}

	if resp.StatusCode() != http.StatusOK {
		return "", "", "", fmt.Errorf("HTTP请求失败，状态码: %d", resp.StatusCode())
	}

	var result Code2SessionResponse
	if err := json.Unmarshal(resp.Body(), &result); err != nil {
		return "", "", "", fmt.Errorf("解析响应失败: %v", err)
	}

	// 检查微信API返回的错误码
	if result.ErrCode != 0 {
		return "", "", "", fmt.Errorf("微信API错误: errcode=%d, errmsg=%s", result.ErrCode, result.ErrMsg)
	}

	if result.OpenID == "" {
		return "", "", "", fmt.Errorf("获取到的openid为空")
	}

	return result.OpenID, result.SessionKey, result.UnionID, nil
}
