// 认证模块：微信登录、用户信息获取和更新
package auth

import (
	"strconv"
	"time"

	"com.sclktx/m/v2/internal/common/model"
	"com.sclktx/m/v2/internal/common/response"
	"com.sclktx/m/v2/internal/common/utils"
	"com.sclktx/m/v2/internal/pkg/config"
	"com.sclktx/m/v2/internal/pkg/wechat"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

type AuthHandler struct {
	db       *gorm.DB
	cfg      *config.Config
	wxClient *wechat.MiniProgramClient
}

func NewAuthHandler(db *gorm.DB, cfg *config.Config, wxClient *wechat.MiniProgramClient) *AuthHandler {
	return &AuthHandler{db: db, cfg: cfg, wxClient: wxClient}
}

type LoginRequest struct {
	Code string `json:"code" binding:"required"`
}

type LoginResponse struct {
	Token    string      `json:"token"`
	UserInfo *UserInfoVO `json:"user_info"`
}

type UserInfoVO struct {
	ID               uint   `json:"id"`
	Openid           string `json:"openid"`
	Nickname         string `json:"nickname"`
	RealName         string `json:"real_name"`
	Phone            string `json:"phone"`
	AvatarURL        string `json:"avatar_url"`
	RoleCode         string `json:"role"`
	RoleName         string `json:"role_name"`
	Status           int    `json:"status"`
	IsFormalEmployee bool   `json:"is_formal_employee"`
	DepartmentName   string `json:"department_name,omitempty"`
	Position         string `json:"position,omitempty"`
}

// Login 微信登录：code 换 openid → 查找或注册用户 → 生成 JWT
// @Summary      微信登录
// @Description  使用微信小程序 code 登录，返回 JWT token 和用户信息
// @Tags         认证
// @Accept       json
// @Produce      json
// @Param        body  body      LoginRequest  true  "微信登录code"
// @Success      200   {object}  response.Response{data=LoginResponse}  "登录成功"
// @Router       /auth/login [post]
func (h *AuthHandler) Login(c *gin.Context) {
	var req LoginRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "参数错误: "+err.Error())
		return
	}

	// 调用微信 code2session 换取 openid
	session, err := h.wxClient.Code2Session(req.Code)
	if err != nil {
		response.BadRequest(c, "微信登录失败: "+err.Error())
		return
	}
	openid := session.OpenID

	var user model.User
	result := h.db.Where("openid = ?", openid).First(&user)

	if result.Error != nil {
		// 新用户注册，分配初始角色（默认访客）
		user = model.User{Openid: openid, Role: "visitor", Status: 1, AvatarURL: h.cfg.System.DefaultAvatar}
		if err := h.db.Create(&user).Error; err != nil {
			response.InternalError(c, "创建用户失败")
			return
		}
	}

	roleCode := user.Role
	if roleCode == "" {
		roleCode = "visitor"
	}

	token, err := utils.GenerateToken(user.ID, roleCode, h.cfg.JWT.Secret, h.cfg.JWT.ExpireHours)
	if err != nil {
		response.InternalError(c, "生成令牌失败")
		return
	}

	// 查询用户部门信息（从 UserDepartment 关联表获取）
	deptName, position := "", ""
	var ud model.UserDepartment
	if err := h.db.Where("user_id = ?", user.ID).First(&ud).Error; err == nil {
		deptName = ud.DepartmentName
		position = ud.Position
	}

	response.Success(c, LoginResponse{
		Token: token,
		UserInfo: &UserInfoVO{
			ID: user.ID, Openid: user.Openid, Nickname: user.Nickname,
			RealName: user.RealName, Phone: user.Phone, AvatarURL: user.AvatarURL,
			RoleCode: roleCode, RoleName: roleNameMap(roleCode),
			Status:           user.Status,
			IsFormalEmployee: roleCode == "employee",
			DepartmentName:   deptName,
			Position:         position,
		},
	})
}

// GetUserInfo 获取当前用户信息
// @Summary      获取当前用户信息
// @Description  获取当前登录用户的详细信息，包含角色、部门、职位等
// @Tags         认证
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Success      200  {object}  response.Response{data=UserInfoVO}  "用户信息"
// @Router       /auth/userinfo [get]
func (h *AuthHandler) GetUserInfo(c *gin.Context) {
	userID := utils.GetUserID(c)
	var user model.User
	if err := h.db.First(&user, userID).Error; err != nil {
		response.Unauthorized(c, "用户不存在，请重新登录")
		return
	}
	roleCode := user.Role
	if roleCode == "" {
		roleCode = "visitor"
	}

	// 查询用户部门信息（从 UserDepartment 关联表获取）
	deptName, position := "", ""
	var ud model.UserDepartment
	if err := h.db.Where("user_id = ?", userID).First(&ud).Error; err == nil {
		deptName = ud.DepartmentName
		position = ud.Position
	}

	response.Success(c, UserInfoVO{
		ID: user.ID, Openid: user.Openid, Nickname: user.Nickname,
		RealName: user.RealName, Phone: user.Phone, AvatarURL: user.AvatarURL,
		RoleCode: roleCode, RoleName: roleNameMap(roleCode),
		Status:           user.Status,
		IsFormalEmployee: roleCode == "employee",
		DepartmentName:   deptName,
		Position:         position,
	})
}

// UpdateUserInfo 更新用户信息（部分更新）
// @Summary      更新用户信息
// @Description  部分更新当前用户的昵称、真实姓名、头像
// @Tags         认证
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        body  body      object{nickname=string,real_name=string,avatar_url=string}  true  "要更新的字段"
// @Success      200   {object}  response.Response  "更新成功"
// @Router       /auth/userinfo [put]
func (h *AuthHandler) UpdateUserInfo(c *gin.Context) {
	userID := utils.GetUserID(c)
	var req struct {
		Nickname  string `json:"nickname"`
		RealName  string `json:"real_name"`
		AvatarURL string `json:"avatar_url"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "参数错误")
		return
	}
	updates := map[string]interface{}{}
	if req.Nickname != "" {
		updates["nickname"] = req.Nickname
	}
	if req.RealName != "" {
		updates["real_name"] = req.RealName
	}
	if req.AvatarURL != "" {
		updates["avatar_url"] = req.AvatarURL
	}
	if err := h.db.Model(&model.User{}).Where("id = ?", userID).Updates(updates).Error; err != nil {
		response.InternalError(c, "更新失败")
		return
	}
	response.SuccessWithMessage(c, "更新成功", nil)
}

// UpdateAvatar 更新用户头像
// @Summary      更新用户头像
// @Description  接受微信图片 URL，直接更新用户头像
// @Tags         用户
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        userId path int true "用户ID"
// @Param        body body object{url=string} true "微信图片URL"
// @Success      200 {object} response.Response "成功"
// @Router       /v1/user/{userId}/avatar [put]
func (h *AuthHandler) UpdateAvatar(c *gin.Context) {
	userID, err := strconv.ParseUint(c.Param("userId"), 10, 64)
	if err != nil {
		response.BadRequest(c, "参数错误")
		return
	}
	var req struct {
		URL string `json:"url" binding:"required"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "参数错误")
		return
	}
	if err := h.db.Model(&model.User{}).Where("id = ?", userID).Update("avatar_url", req.URL).Error; err != nil {
		response.InternalError(c, "更新失败")
		return
	}
	response.SuccessWithMessage(c, "更新成功", nil)
}

// BindPhone 绑定手机号（微信解密）
// @Summary      绑定手机号
// @Description  通过微信加密数据解密并绑定手机号
// @Tags         认证
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        body  body      object{code=string,encrypted_data=string,iv=string}  true  "微信加密数据"
// @Success      200   {object}  response.Response  "绑定成功"
// @Router       /auth/phone [post]
func (h *AuthHandler) BindPhone(c *gin.Context) {
	userID := utils.GetUserID(c)
	var req struct {
		Code          string `json:"code" binding:"required"`
		EncryptedData string `json:"encrypted_data" binding:"required"`
		Iv            string `json:"iv" binding:"required"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "参数错误")
		return
	}

	// 用 code 换取 session_key
	session, err := h.wxClient.Code2Session(req.Code)
	if err != nil {
		response.BadRequest(c, "微信授权失败")
		return
	}

	// 解密手机号
	phone, err := h.wxClient.DecryptPhone(session.SessionKey, req.EncryptedData, req.Iv)
	if err != nil {
		response.BadRequest(c, "手机号解密失败")
		return
	}

	if err := h.db.Model(&model.User{}).Where("id = ?", userID).Updates(map[string]interface{}{
		"phone": phone, "phone_verified": true,
	}).Error; err != nil {
		response.InternalError(c, "绑定失败")
		return
	}

	// 自动匹配待确认员工：手机号匹配则升级为正式员工
	var pending model.PendingEmployee
	if err := h.db.Where("phone = ? AND is_matched = ?", phone, false).First(&pending).Error; err == nil {
		now := time.Now()
		// 创建 UserDepartment
		ud := model.UserDepartment{
			UserID:         userID,
			DepartmentID:   pending.DepartmentID,
			DepartmentName: pending.DepartmentName,
			Position:       pending.Position,
			EmployeeType:   pending.EmployeeType,
			EmployeeStatus: 1,
		}
		h.db.Where("user_id = ?", userID).Assign(ud).FirstOrCreate(&model.UserDepartment{UserID: userID})

		// 升级用户角色
		h.db.Model(&model.User{}).Where("id = ?", userID).Update("role", "employee")

		// 标记已匹配
		h.db.Model(&pending).Updates(map[string]interface{}{
			"is_matched":     true,
			"matched_user_id": &userID,
			"matched_at":     &now,
		})
	}

	response.SuccessWithMessage(c, "绑定成功", nil)
}

// MockLogin 模拟登录（开发调试用）：直接登录 id=1 的用户
// @Summary      模拟登录
// @Description  直接登录 id=1 的账号，返回与微信登录一致的 token 和用户信息
// @Tags         认证
// @Accept       json
// @Produce      json
// @Success      200  {object}  response.Response{data=LoginResponse}  "登录成功"
// @Router       /auth/mock-login [post]
func (h *AuthHandler) MockLogin(c *gin.Context) {
	var user model.User
	if err := h.db.First(&user, 1).Error; err != nil {
		response.NotFound(c, "用户不存在")
		return
	}

	roleCode := user.Role
	if roleCode == "" {
		roleCode = "visitor"
	}

	token, err := utils.GenerateToken(user.ID, roleCode, h.cfg.JWT.Secret, h.cfg.JWT.ExpireHours)
	if err != nil {
		response.InternalError(c, "生成令牌失败")
		return
	}

	// 查询用户部门信息（从 UserDepartment 关联表获取）
	deptName, position := "", ""
	var ud model.UserDepartment
	if err := h.db.Where("user_id = ?", user.ID).First(&ud).Error; err == nil {
		deptName = ud.DepartmentName
		position = ud.Position
	}

	response.Success(c, LoginResponse{
		Token: token,
		UserInfo: &UserInfoVO{
			ID: user.ID, Openid: user.Openid, Nickname: user.Nickname,
			RealName: user.RealName, Phone: user.Phone, AvatarURL: user.AvatarURL,
			RoleCode: roleCode, RoleName: roleNameMap(roleCode),
			Status:           user.Status,
			IsFormalEmployee: roleCode == "employee",
			DepartmentName:   deptName,
			Position:         position,
		},
	})
}

func (h *AuthHandler) RegisterRoutes(r *gin.RouterGroup) {
	auth := r.Group("/auth")
	{
		auth.POST("/login", h.Login)
		auth.POST("/mock-login", h.MockLogin)
	}
}

// RegisterAuthRoutes 注册需要 JWT 认证的 auth 路由
func (h *AuthHandler) RegisterAuthRoutes(r *gin.RouterGroup) {
	auth := r.Group("/auth")
	{
		auth.GET("/userinfo", h.GetUserInfo)
		auth.PUT("/userinfo", h.UpdateUserInfo)
		auth.POST("/phone", h.BindPhone)
	}
	// 头像更新
	r.PUT("/user/:userId/avatar", h.UpdateAvatar)
}

// roleNameMap 角色编码 → 中文名
func roleNameMap(code string) string {
	switch code {
	case "employee":
		return "员工"
	case "guard":
		return "保安"
	default:
		return "访客"
	}
}
