package user

import (
	"errors"
	logger "eta/eta_mini_ht_api/common/component/log"
	"eta/eta_mini_ht_api/common/exception"
	analystService "eta/eta_mini_ht_api/domian/financial_analyst"
	userService "eta/eta_mini_ht_api/domian/user"
	"gorm.io/gorm"
	"sort"
	"sync"
	"time"
)

const (
	RiskValid   = "valid"
	RiskExpired = "expired"
	RiskUnTest  = "unTest"
)

type User struct {
	Id       int    `json:"id"`
	Username string `json:"username"`
	Mobile   string `json:"mobile"`
	OpenId   string `json:"openId,omitempty"`
}

type AnalystDetail struct {
	AnalystName  string `json:"AnalystName"`
	HeadImgUrl   string `json:"HeadImgUrl"`
	Introduction string `json:"Introduction"`
	Followed     string `json:"Followed"`
}

type UserProfile struct {
	Mobile          string `json:"mobile"`
	RiskLevel       string `json:"riskLevel"`
	RiskLevelStatus string `json:"riskLevelStatus"`
	UserName        string `json:"userName"`
}

func convertUserDTOToProfile(dto userService.UserDTO) (profile UserProfile) {
	profile = UserProfile{
		Mobile:    dto.Mobile,
		RiskLevel: dto.RiskLevel,
		UserName:  dto.Username,
	}
	if profile.UserName == "" {
		profile.UserName = dto.Mobile
	}
	if dto.RiskLevel == "" {
		profile.RiskLevelStatus = RiskUnTest
		return
	}
	date, err := time.Parse(time.DateOnly, dto.RiskValidEndDate)
	if err != nil {
		logger.Error("解析日期失败:%v", err)
		profile.RiskLevelStatus = RiskExpired
		return
	}
	currentDate := time.Now().Truncate(24 * time.Hour)
	expiryDate := date.Truncate(24 * time.Hour)
	if expiryDate.Before(currentDate) {
		profile.RiskLevelStatus = RiskExpired
		return
	}
	profile.RiskLevelStatus = RiskValid
	return
}
func GetUserProfile(userId int) (userProfile UserProfile, err error) {
	userDTO, err := userService.GetUserById(userId)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			logger.Error("用户不存在,用户Id:%d", userId)
			err = exception.New(exception.TemplateUserNotFound)
		} else {
			logger.Error("获取用户信息失败:%v", err)
			err = exception.New(exception.TemplateUserFoundFailed)
		}
		return
	}
	userProfile = convertUserDTOToProfile(userDTO)
	return
}
func GetAnalystDetail(userId int, analystId int) (analystDetail AnalystDetail, err error) {
	analyst, err := analystService.GetAnalystById(analystId)
	if err != nil {
		logger.Error("研究员信息不存在:%v", err)
		err = exception.New(exception.AnalystNotFound)
	}
	analystDetail = convertToAnalystDetail(analyst)
	//研究员关注状态
	analystDetail.Followed = userService.GetFollowed(userId, analystId)
	return

}

func convertToAnalystDetail(dto analystService.FinancialAnalystDTO) AnalystDetail {
	return AnalystDetail{
		AnalystName:  dto.Name,
		HeadImgUrl:   dto.HeadImgUrl,
		Introduction: dto.Introduction,
	}

}
func FollowAnalystsByName(userId int, analystNames []string, followType string) (err error) {
	var followlist []userService.FollowDTO
	for _, analystName := range analystNames {
		FinancialAnalystDTO, followErr := analystService.GetAnalystByName(analystName)
		if followErr != nil {

			err = exception.New(exception.AnalystNotFound)
		}
		if FinancialAnalystDTO.Id == 0 || FinancialAnalystDTO.Name == "" {
			continue
		}
		followDTO := userService.FollowDTO{
			UserId:      userId,
			AnalystId:   FinancialAnalystDTO.Id,
			AnalystName: FinancialAnalystDTO.Name,
			FollowType:  followType,
		}
		followlist = append(followlist, followDTO)
	}
	err = userService.FollowAnalystsByName(userId, followlist, followType)
	if err != nil {
		logger.Error("批量关注研究员失败:%v", err)
		err = exception.New(exception.BatchFollowingAnalystFailed)
	}
	return
}
func CheckFollowStatusByNames(userId int, names []string) (list []userService.FollowDTO, err error) {
	list, err = userService.CheckFollowStatusByNames(userId, names)
	if err != nil {
		logger.Error("获取关注状态失败:%v", err)
		err = exception.New(exception.CheckFollowStatusByNamesFailed)
	}
	return
}
func FollowAnalyst(userId int, analystId int, followType string) (err error) {
	FinancialAnalystDTO, err := analystService.GetAnalystById(analystId)
	if err != nil {
		err = exception.New(exception.AnalystNotFound)
	}
	if FinancialAnalystDTO.Id == 0 || FinancialAnalystDTO.Name == "" {
		err = exception.New(exception.AnalystNotFound)
		return
	}
	followDTO := userService.FollowDTO{
		UserId:      userId,
		AnalystId:   analystId,
		AnalystName: FinancialAnalystDTO.Name,
		FollowType:  followType,
	}
	err = userService.FollowAnalyst(followDTO)
	if err != nil {
		logger.Error("关注研究员失败:%v", err)
		err = exception.New(exception.UserFollowAnalystFailed)
	}
	return
}
func GetFollowingAnalystList(userId int) (analysts []FollowAnalystDTO, err error) {
	logger.Info("用户ID:%d", userId)
	dtoList, err := userService.GetFollowingAnalystList(userId)
	if err != nil {
		logger.Error("获取关注列表失败:%v", err)
		err = exception.New(exception.GetFollowingAnalystListFailed)
		return
	}
	analysts, err = convertToAnalystList(dtoList)
	var wg sync.WaitGroup
	wg.Add(len(analysts))
	for i := 0; i < len(analysts); i++ {
		go func(followDTo *FollowAnalystDTO) {
			defer wg.Done()
			followDTo.NeedNotice = userService.NeedNotice(userId, followDTo.AnalystId)
			var analystsDTO analystService.FinancialAnalystDTO
			analystsDTO, err = analystService.GetAnalystById(followDTo.AnalystId)
			if err != nil {
				logger.Error("获取研究员信息失败")
			} else {
				followDTo.HeadImgUrl = analystsDTO.HeadImgUrl
			}
		}(&analysts[i])
	}
	wg.Wait()
	//排序
	sort.Slice(analysts, func(i, j int) bool {
		// 首先按 NeedNotice 排序
		if analysts[i].NeedNotice == analysts[j].NeedNotice {
			// 对于 NeedNotice 相同的情况下,进行倒序排列
			return analysts[i].FollowedTime.After(analysts[j].FollowedTime)
		}
		// NeedNotice 为 true 的排在 false 的前面
		return analysts[i].NeedNotice
	})
	//if err != nil {
	//	logger.Error("转换研究员列表失败:%v", err)
	//	err = exception.New(exception.TransferFollowingAnalystListFailed)
	//}
	return
}

func GetUnReadMessageList(userId int) (messages []userService.MyMessage, err error) {
	messages, err = userService.GetUnReadMessageList(userId)
	if err != nil {
		err = exception.New(exception.GetUserUnReadMsgFailed)
	}
	return
}
func ReadMessage(userId int, messageId int) bool {
	return userService.ReadMessage(userId, messageId)
}

func ReadMessages(userId int, analystId int) bool {
	return userService.ReadMessages(userId, analystId)
}

type FollowAnalystDTO struct {
	AnalystId    int       `json:"analystId"`
	AnalystName  string    `json:"analystName"`
	HeadImgUrl   string    `json:"headImgUrl"`
	FollowedTime time.Time `json:"followedTime"`
	NeedNotice   bool      `json:"needNotice"`
}

func convertToAnalystList(dtoList []userService.FollowDTO) (list []FollowAnalystDTO, err error) {
	for _, dto := range dtoList {
		analyst := FollowAnalystDTO{
			AnalystId:    dto.AnalystId,
			AnalystName:  dto.AnalystName,
			FollowedTime: dto.FollowedTime,
			NeedNotice:   false,
		}
		list = append(list, analyst)
	}
	return
}

func FollowAnalystByName(userId int, analystName string, followType string) (err error) {
	FinancialAnalystDTO, err := analystService.GetAnalystByName(analystName)
	if err != nil {
		err = exception.New(exception.AnalystNotFound)
	}
	if FinancialAnalystDTO.Id == 0 || FinancialAnalystDTO.Name == "" {
		err = exception.New(exception.AnalystNotFound)
		return
	}
	followDTO := userService.FollowDTO{
		UserId:      userId,
		AnalystId:   FinancialAnalystDTO.Id,
		AnalystName: FinancialAnalystDTO.Name,
		FollowType:  followType,
	}
	err = userService.FollowAnalyst(followDTO)
	if err != nil {
		logger.Error("关注研究员失败:%v", err)
		err = exception.New(exception.UserFollowAnalystFailed)
	}
	return
}
func FeedBack(userId int, mobile string, message string) (err error) {
	feedback := userService.FeedbackDTO{
		UserId:  userId,
		Mobile:  mobile,
		Message: message,
	}
	err = userService.FeedBack(feedback)
	if err != nil {
		err = exception.New(exception.FeedBackError)
	}
	return
}

func GetUserByMobile(mobile string) (user User, err error) {
	userDTO, err := userService.GetUserByMobile(mobile)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			err = exception.New(exception.TemplateUserNotFound)
		} else {
			err = exception.New(exception.TemplateUserFoundFailed)
		}
	}
	user = convertToUser(userDTO)
	return
}

func GetUserByOpenId(openId string) (user User, err error) {
	userDTO, err := userService.GetUserByOpenId(openId)
	if err != nil {
		return
	}
	user = convertToUser(userDTO)
	return
}

func convertToUser(userDTO userService.UserDTO) User {
	return User{
		Id:       userDTO.Id,
		Username: userDTO.Username,
		OpenId:   userDTO.OpenId,
		Mobile:   userDTO.Mobile,
	}
}