package auth

import (
	"context"
	"errors"
	"strings"

	"github.com/google/uuid"
	"gorm.io/gorm"

	"dudu/server/internal/store"
)

// WechatIdentityInfo 微信授权换取的身份。
type WechatIdentityInfo struct {
	OpenID   string
	UnionID  string
	Nickname string
	Avatar   string
}

// WechatClient 微信 OAuth 客户端抽象：真实实现走开放平台 API（2A 凭证就绪后接入），
// 开发期用 MockWechat。
type WechatClient interface {
	// ExchangeCode code 换身份；appType: web | mobile
	ExchangeCode(ctx context.Context, code, appType string) (WechatIdentityInfo, error)
}

// MockWechat 开发期 mock：code 直接映射 openid（同 code 幂等同一用户），
// unionid = openid 加前缀，昵称取 code 前 8 字符。
type MockWechat struct{}

func (MockWechat) ExchangeCode(_ context.Context, code, _ string) (WechatIdentityInfo, error) {
	if code == "" {
		return WechatIdentityInfo{}, errors.New("empty code")
	}
	nick := code
	if len(nick) > 8 {
		nick = nick[:8]
	}
	return WechatIdentityInfo{
		OpenID:   "mock-open-" + code,
		UnionID:  "mock-union-" + code,
		Nickname: nick,
	}, nil
}

// MaskNickname 昵称脱敏："wangjia" → "wang***"；中文取首字 + ***。
func MaskNickname(n string) string {
	r := []rune(strings.TrimSpace(n))
	if len(r) == 0 {
		return "用户***"
	}
	keep := 4
	if r[0] > 0x2E80 { // CJK 起始附近，中文名只保留首字
		keep = 1
	}
	if len(r) < keep {
		keep = len(r)
	}
	return string(r[:keep]) + "***"
}

// FindOrCreateUser unionid 优先关联（同一用户多端 openid 归一），其次 openid。
func FindOrCreateUser(db *gorm.DB, info WechatIdentityInfo, appType string) (*store.User, error) {
	var ident store.WechatIdentity
	err := db.Where("open_id = ?", info.OpenID).First(&ident).Error
	if err == nil {
		var u store.User
		return &u, db.First(&u, "id = ?", ident.UserID).Error
	}
	if !errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, err
	}

	var user store.User
	err = db.Transaction(func(tx *gorm.DB) error {
		// unionid 已存在 → 关联到既有用户
		if info.UnionID != "" {
			var other store.WechatIdentity
			if err := tx.Where("union_id = ?", info.UnionID).First(&other).Error; err == nil {
				if err := tx.First(&user, "id = ?", other.UserID).Error; err != nil {
					return err
				}
				return tx.Create(&store.WechatIdentity{
					UserID: user.ID, OpenID: info.OpenID, UnionID: info.UnionID, AppType: appType,
				}).Error
			}
		}
		// 新用户
		user = store.User{
			ID:       strings.ReplaceAll(uuid.NewString(), "-", "")[:24],
			Nickname: info.Nickname, AvatarURL: info.Avatar,
		}
		if err := tx.Create(&user).Error; err != nil {
			return err
		}
		return tx.Create(&store.WechatIdentity{
			UserID: user.ID, OpenID: info.OpenID, UnionID: info.UnionID, AppType: appType,
		}).Error
	})
	return &user, err
}
