package handler

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gouki/lunar-server/internal/config"
	"github.com/gouki/lunar-server/internal/model"
	"github.com/gouki/lunar-server/internal/service"
)

// code2Session 调用微信 jscode2session 接口换取 openid
// session_key 仅保存在服务端，绝不下发给客户端
func code2Session(code string) (openID, unionID string, err error) {
	cfg := config.Load()
	if cfg.Wechat.AppID == "" || cfg.Wechat.AppSecret == "" {
		return "", "", fmt.Errorf("wechat appid/secret not configured")
	}

	query := url.Values{
		"appid":      {cfg.Wechat.AppID},
		"secret":     {cfg.Wechat.AppSecret},
		"js_code":    {code},
		"grant_type": {"authorization_code"},
	}

	client := &http.Client{Timeout: 10 * time.Second}
	resp, err := client.Get("https://api.weixin.qq.com/sns/jscode2session?" + query.Encode())
	if err != nil {
		return "", "", fmt.Errorf("jscode2session request failed: %w", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(io.LimitReader(resp.Body, 64*1024))
	if err != nil {
		return "", "", fmt.Errorf("read jscode2session response failed: %w", err)
	}

	var result struct {
		OpenID  string `json:"openid"`
		UnionID string `json:"unionid"`
		ErrCode int    `json:"errcode"`
		ErrMsg  string `json:"errmsg"`
	}
	if err := json.Unmarshal(body, &result); err != nil {
		return "", "", fmt.Errorf("parse jscode2session response failed: %w", err)
	}
	if result.ErrCode != 0 || result.OpenID == "" {
		return "", "", fmt.Errorf("wechat auth failed: errcode=%d errmsg=%s", result.ErrCode, result.ErrMsg)
	}
	return result.OpenID, result.UnionID, nil
}

// upsertUser 根据 openid 获取用户，不存在则创建
func upsertUser(openID, unionID string) (*model.User, error) {
	userService := service.NewUserService()
	user, err := userService.GetUserByOpenID(openID)
	if err != nil {
		return nil, err
	}

	if user == nil {
		user = &model.User{
			OpenID:   openID,
			UnionID:  unionID,
			Nickname: "微信用户",
			Status:   1,
		}
		if err := userService.CreateUser(user); err != nil {
			return nil, err
		}
	}
	return user, nil
}

// UserLogin 用户登录（小程序 wx.login 的 code 换取 token）
func UserLogin(c *gin.Context) {
	var req struct {
		Code string `json:"code" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": 400,
			"msg":  "参数错误",
		})
		return
	}

	openID, unionID, err := code2Session(req.Code)
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{
			"code": 401,
			"msg":  "微信登录失败",
		})
		return
	}

	user, err := upsertUser(openID, unionID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "创建用户失败",
		})
		return
	}

	// 禁用用户不允许登录
	if user.Status != 1 {
		c.JSON(http.StatusForbidden, gin.H{
			"code": 403,
			"msg":  "账号已被禁用",
		})
		return
	}

	cfg := config.Load()
	userService := service.NewUserService()
	token, err := userService.GenerateToken(user.ID, cfg.JWT.Secret)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "生成token失败",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "success",
		"data": gin.H{
			"token": token,
			"user":  user,
		},
	})
}

// UserLogout 用户登出
func UserLogout(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "success",
	})
}

// GetUserProfile 获取用户资料
func GetUserProfile(c *gin.Context) {
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{
			"code": 401,
			"msg":  "未授权",
		})
		return
	}

	userService := service.NewUserService()
	user, err := userService.GetUserByID(userID.(uint))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "获取用户信息失败",
		})
		return
	}

	profile, _ := userService.GetUserProfile(user.ID)

	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "success",
		"data": gin.H{
			"user":    user,
			"profile": profile,
		},
	})
}

// UpdateUserProfile 更新用户资料
func UpdateUserProfile(c *gin.Context) {
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{
			"code": 401,
			"msg":  "未授权",
		})
		return
	}

	var req struct {
		Nickname      string `json:"nickname"`
		Avatar        string `json:"avatar"`
		Gender        int    `json:"gender"`
		RealName      string `json:"realName"`
		Birthday      string `json:"birthday"`
		BirthTime     string `json:"birthTime"`
		Zodiac        string `json:"zodiac"`
		Constellation string `json:"constellation"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": 400,
			"msg":  "参数错误",
		})
		return
	}

	userService := service.NewUserService()

	// 更新用户基本信息
	user, err := userService.GetUserByID(userID.(uint))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "获取用户信息失败",
		})
		return
	}

	if req.Nickname != "" {
		user.Nickname = req.Nickname
	}
	if req.Avatar != "" {
		user.Avatar = req.Avatar
	}
	if req.Gender > 0 {
		user.Gender = req.Gender
	}

	if err := userService.UpdateUser(user); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "更新用户信息失败",
		})
		return
	}

	// 更新用户资料
	profile, _ := userService.GetUserProfile(user.ID)
	if profile == nil {
		profile = &model.UserProfile{
			UserID: user.ID,
		}
	}

	if req.RealName != "" {
		profile.RealName = req.RealName
	}
	if req.Birthday != "" {
		profile.Birthday = req.Birthday
	}
	if req.BirthTime != "" {
		profile.BirthTime = req.BirthTime
	}
	if req.Zodiac != "" {
		profile.Zodiac = req.Zodiac
	}
	if req.Constellation != "" {
		profile.Constellation = req.Constellation
	}

	if err := userService.UpdateUserProfile(profile); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "更新用户资料失败",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "success",
		"data": gin.H{
			"user":    user,
			"profile": profile,
		},
	})
}

// GetBirthProfiles 获取当前用户的生辰档案列表
func GetBirthProfiles(c *gin.Context) {
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "未授权"})
		return
	}

	userService := service.NewUserService()
	profiles, err := userService.ListBirthProfiles(userID.(uint))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": "获取生辰档案失败"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "success",
		"data": gin.H{
			"profiles":   profiles,
			"maxFree":    model.MaxFreeBirthProfiles,
		},
	})
}

// CreateBirthProfile 新增生辰档案（每用户免费上限 MaxFreeBirthProfiles 个）
func CreateBirthProfile(c *gin.Context) {
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "未授权"})
		return
	}

	var req struct {
		Name      string `json:"name"`
		Gender    int    `json:"gender"`
		Birthday  string `json:"birthday" binding:"required"`
		BirthTime string `json:"birthTime" binding:"required"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "参数错误"})
		return
	}

	// 简单格式校验
	if _, err := time.Parse("2006-01-02", req.Birthday); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "出生日期格式错误"})
		return
	}
	if _, err := time.Parse("15:04", req.BirthTime); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "出生时间格式错误"})
		return
	}
	if req.Gender != 1 && req.Gender != 2 {
		req.Gender = 1
	}

	profile := &model.BirthProfile{
		UserID:    userID.(uint),
		Name:      req.Name,
		Gender:    req.Gender,
		Birthday:  req.Birthday,
		BirthTime: req.BirthTime,
	}

	userService := service.NewUserService()
	if err := userService.CreateBirthProfile(profile); err != nil {
		if err == service.ErrBirthProfileLimit {
			c.JSON(http.StatusForbidden, gin.H{"code": 403, "msg": err.Error()})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": "新增生辰档案失败"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "success",
		"data": gin.H{"profile": profile},
	})
}

// DeleteBirthProfile 删除生辰档案（仅限本人）
func DeleteBirthProfile(c *gin.Context) {
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "未授权"})
		return
	}

	id, err := strconv.ParseUint(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "参数错误"})
		return
	}

	userService := service.NewUserService()
	if err := userService.DeleteBirthProfile(uint(id), userID.(uint)); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": "删除生辰档案失败"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success"})
}

// WechatAuth 微信授权（仅返回 openid，session_key 属敏感凭证不下发）
func WechatAuth(c *gin.Context) {
	var req struct {
		Code string `json:"code" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": 400,
			"msg":  "参数错误",
		})
		return
	}

	openID, _, err := code2Session(req.Code)
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{
			"code": 401,
			"msg":  "微信授权失败",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "success",
		"data": gin.H{
			"openid": openID,
		},
	})
}
