package user

import (
	"bytes"
	"context"
	"encoding/base64"
	"errors"
	"image/png"

	"bindbox-game/internal/pkg/douyin"
	"bindbox-game/internal/repository/mysql/dao"
	"bindbox-game/internal/repository/mysql/model"

	randomname "github.com/DanPlayer/randomname"
	identicon "github.com/issue9/identicon/v2"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
)

// LoginDouyinInput 抖音登录输入参数
type LoginDouyinInput struct {
	Code          string // tt.login 获取的 code
	AnonymousCode string // 匿名登录 code
	Nickname      string
	AvatarURL     string
	InviteCode    string
	ChannelCode   string
}

// LoginDouyinOutput 抖音登录输出结果
type LoginDouyinOutput struct {
	User      *model.Users
	IsNewUser bool
	InviterID int64
}

// LoginDouyin 抖音小程序登录
func (s *service) LoginDouyin(ctx context.Context, in LoginDouyinInput) (*LoginDouyinOutput, error) {
	// 1. 调用抖音 code2session 获取 openid
	if in.Code == "" && in.AnonymousCode == "" {
		return nil, errors.New("code 或 anonymous_code 不能为空")
	}

	resp, err := douyin.Code2Session(ctx, in.Code, in.AnonymousCode)
	if err != nil {
		s.logger.Error("抖音 code2session 失败", zap.Error(err))
		return nil, err
	}

	openID := resp.Data.OpenID
	if openID == "" {
		openID = resp.Data.AnonymousOpenID
	}
	if openID == "" {
		return nil, errors.New("获取抖音 openid 失败")
	}

	unionID := resp.Data.UnionID

	var u *model.Users
	// 事务处理：创建/更新用户 + 处理邀请
	var isNewUser bool
	var inviterID int64
	err = s.writeDB.Transaction(func(tx *dao.Query) error {
		var err error

		// 2. 先通过 douyin_id 查找用户
		u, err = tx.Users.WithContext(ctx).Clauses(clause.Locking{Strength: "UPDATE"}).
			Where(tx.Users.DouyinID.Eq(openID)).First()
		if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
			return err
		}

		// 3. 如果有 unionid，尝试通过 unionid 关联到已有的微信用户
		if u == nil && unionID != "" {
			u, err = tx.Users.WithContext(ctx).Clauses(clause.Locking{Strength: "UPDATE"}).
				Where(tx.Users.Unionid.Eq(unionID)).First()
			if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
				return err
			}
			// 找到微信用户，绑定抖音ID
			if u != nil && u.DouyinID == "" {
				_, _ = tx.Users.WithContext(ctx).Where(tx.Users.ID.Eq(u.ID)).
					Updates(map[string]any{"douyin_id": openID})
				u.DouyinID = openID
			}
		}

		// 查找渠道ID
		var channelID int64
		if in.ChannelCode != "" {
			ch, _ := s.readDB.Channels.WithContext(ctx).Where(s.readDB.Channels.Code.Eq(in.ChannelCode)).First()
			if ch != nil {
				channelID = ch.ID
			}
		}

		// 4. 如果用户不存在，创建新用户
		isNewUser = false
		if u == nil {
			isNewUser = true
			code := s.generateInviteCode(ctx)
			nickname := in.Nickname
			if nickname == "" {
				nickname = randomname.GenerateName()
			}
			avatar := in.AvatarURL
			if avatar == "" {
				seed := openID
				if seed == "" {
					seed = nickname
				}
				img := identicon.S2(128).Make([]byte(seed))
				var buf bytes.Buffer
				_ = png.Encode(&buf, img)
				avatar = "data:image/png;base64," + base64.StdEncoding.EncodeToString(buf.Bytes())
			}
			u = &model.Users{
				Nickname:   nickname,
				Avatar:     avatar,
				DouyinID:   openID,
				Unionid:    unionID,
				InviteCode: code,
				Status:     1,
				ChannelID:  channelID,
			}
			if err := tx.Users.WithContext(ctx).Create(u); err != nil {
				return err
			}
		} else {
			// 更新用户信息
			set := map[string]any{}
			if in.Nickname != "" && u.Nickname == "" {
				set["nickname"] = in.Nickname
			}
			if in.AvatarURL != "" && u.Avatar == "" {
				set["avatar"] = in.AvatarURL
			}
			if unionID != "" && u.Unionid == "" {
				set["unionid"] = unionID
			}
			if channelID > 0 && u.ChannelID == 0 {
				set["channel_id"] = channelID
			}
			if len(set) > 0 {
				if _, err := tx.Users.WithContext(ctx).Where(tx.Users.ID.Eq(u.ID)).Updates(set); err != nil {
					return err
				}
				u, _ = tx.Users.WithContext(ctx).Where(tx.Users.ID.Eq(u.ID)).First()
			}
		}

		// 5. 处理邀请逻辑
		// 只有在真正创建新用户记录时才发放邀请奖励，防止多账号切换重复刷奖励
		if in.InviteCode != "" && isNewUser {
			// 查询邀请人
			var inviter model.Users
			// First() 返回 (result, error)
			inviterResult, err := tx.Users.WithContext(ctx).Where(tx.Users.InviteCode.Eq(in.InviteCode)).First()
			if err == nil && inviterResult != nil && inviterResult.ID != u.ID {
				inviter = *inviterResult
				// 创建邀请记录
				invite := &model.UserInvites{
					InviteeID:  u.ID, // UserID -> InviteeID
					InviterID:  inviter.ID,
					InviteCode: in.InviteCode,
					// Status:    1, // Removed
				}
				if err := tx.UserInvites.WithContext(ctx).Create(invite); err != nil {
					return err
				}

				// 更新被邀请人的邀请人ID
				// UpdateColumn for single column update
				if _, err := tx.Users.WithContext(ctx).Where(tx.Users.ID.Eq(u.ID)).
					UpdateColumn(tx.Users.InviterID, inviter.ID); err != nil {
					return err
				}

				// 返回邀请人ID，以便外层触发任务中心逻辑
				inviterID = inviter.ID
				s.logger.Info("抖音登录邀请关系建立成功", zap.Int64("user_id", u.ID), zap.Int64("inviter_id", inviter.ID))
			}
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	return &LoginDouyinOutput{
		User:      u,
		IsNewUser: isNewUser,
		InviterID: inviterID,
	}, nil
}
