package user

import (
	errs "backend/pkg/library/errors"
	mbr "backend/pkg/member/domain/member"
	member "backend/pkg/member/domain/usecase"
	"backend/pkg/permission/domain/token"
	"context"
	"fmt"
	"math"
	"time"

	"backend/internal/svc"
	"backend/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type UpdateUserInfoLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

// NewUpdateUserInfoLogic 更新當前登入的會員資訊
func NewUpdateUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateUserInfoLogic {
	return &UpdateUserInfoLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *UpdateUserInfoLogic) UpdateUserInfo(req *types.UpdateUserInfoReq) (resp *types.UserInfoResp, err error) {
	update, err := ConvertBindingUserInfoToUpdateRequest(token.UID(l.ctx), req)
	if err != nil {
		return nil, errs.InputInvalidFormatError("failed to get correct user info", err.Error())
	}

	err = l.svcCtx.AccountUC.UpdateUserInfo(l.ctx, update)
	if err != nil {
		return nil, err
	}
	info, err := l.svcCtx.AccountUC.GetUserInfo(l.ctx, member.GetUserInfoRequest{
		UID: token.UID(l.ctx),
	})
	if err != nil {
		return nil, err
	}

	accountInfo, err := l.svcCtx.AccountUC.GetUserAccountInfo(l.ctx, member.GetUIDByAccountRequest{Account: token.LoginID(l.ctx)})
	if err != nil {
		return nil, err
	}

	res := &types.UserInfoResp{
		UID:               token.UID(l.ctx),
		Platform:          accountInfo.Data.Platform.ToString(),
		UserStatus:        info.UserStatus.CodeToString(),
		PreferredLanguage: info.PreferredLanguage,
		Currency:          info.Currency,
		UpdateAt:          time.Unix(0, info.CreateTime).UTC().Format(time.RFC3339),
		CreateAt:          time.Unix(0, info.UpdateTime).UTC().Format(time.RFC3339),
		//Role              string `json:"role"`
	}
	if info.Address != nil {
		res.Address = *info.Address
	}
	if info.AvatarURL != nil {
		res.AvatarURL = *info.AvatarURL
	}
	if info.FullName != nil {
		res.FullName = *info.FullName
	}
	if info.PhoneNumber != nil {
		res.PhoneNumber = *info.PhoneNumber
		res.IsPhoneVerified = true
	}
	if info.Nickname != nil {
		res.Nickname = *info.Nickname
	}
	if info.Email != nil {
		res.Email = *info.Email
		res.IsEmailVerified = true
	}
	if info.GenderCode != nil {
		res.GenderCode = mbr.GetGenderByCode(*info.GenderCode)
	}
	if info.Birthdate != nil {
		res.Birthdate = toStringStr(info.Birthdate)
	}

	return res, nil
}

func toStringStr(n *int64) string {
	result := ""
	if n != nil {
		result = time.Unix(*n, 0).UTC().Format(time.RFC3339)
	}

	return result
}

func ConvertBindingUserInfoToUpdateRequest(uid string, bindingInfo *types.UpdateUserInfoReq) (*member.UpdateUserInfoRequest, error) {
	updateRequest := &member.UpdateUserInfoRequest{
		UID:               uid,
		AvatarURL:         bindingInfo.AvatarURL,
		FullName:          bindingInfo.FullName,
		Nickname:          bindingInfo.Nickname,
		Address:           bindingInfo.Address,
		PreferredLanguage: bindingInfo.PreferredLanguage,
		Currency:          bindingInfo.Currency,
	}

	// Convert GenderCode from string to *int8
	if &bindingInfo.GenderCode != nil {
		gender := mbr.GetGenderCodeByStr(*bindingInfo.GenderCode)
		// 檢查 gender 是否在 int8 範圍內
		if gender < math.MinInt8 || gender > math.MaxInt8 {
			return nil, fmt.Errorf("gender code %d is out of int8 range", gender)
		}
		genderInt8 := int8(gender)
		updateRequest.GenderCode = &genderInt8
	}

	// Convert Birthdate from string to *int64
	if &bindingInfo.Birthdate != nil {
		parse, err := time.Parse(time.RFC3339, *bindingInfo.Birthdate)
		if err != nil {
			return nil, err
		}
		date := parse.Unix()

		updateRequest.Birthdate = &date
	}

	return updateRequest, nil
}
