package user

import (
	"errors"
	logger "eta/eta_mini_ht_api/common/component/log"
	"eta/eta_mini_ht_api/models"
	"gorm.io/gorm"
	"time"
)

type FollowingType string

const (
	Following   FollowingType = "following"
	Unfollowed  FollowingType = "unfollowed"
	listColumns               = "user_id, financial_analyst_id,financial_analyst_name, followed,followed_time"

	FollowingStatusColumns = "financial_analyst_id,financial_analyst_name, followed"
)

// UserAnalystFollowList 代表用户关注的研究员列表
type UserAnalystFollowList struct {
	ID                   int           `gorm:"primary_key;auto_increment;column:id"`
	UserID               int           `gorm:"not null;index:user_id"`
	FinancialAnalystID   int           `gorm:"not null;index:financial_analyst_id"`
	FinancialAnalystName string        `gorm:"not null;size:100"`
	Followed             FollowingType `gorm:"type:enum('following', 'unfollowed');not null"`
	FollowedTime         time.Time     `gorm:"type:timestamp;not null;default:CURRENT_TIMESTAMP;onupdate:CURRENT_TIMESTAMP"`
	CreatedTime          time.Time     `gorm:"type:timestamp;not null;default:0000-00-00 00:00:00"`
	UpdatedTime          time.Time     `gorm:"type:timestamp;null;onupdate:CURRENT_TIMESTAMP"`
}

func GetPostUser(authorName string, PublishTime string) (ids []int) {
	db := models.Main()
	err := db.Model(&UserAnalystFollowList{}).Select("distinct user_id").Where("financial_analyst_name = ? and followed = ? and followed_time <=?", authorName, Following, PublishTime).Order("id asc").Find(&ids).Error
	if err != nil {
		return []int{}
	}
	return
}

func (fa UserAnalystFollowList) TableName() string {
	return "user_analyst_follow_list"
}
func (fa *UserAnalystFollowList) BeforeCreate(_ *gorm.DB) (err error) {
	fa.CreatedTime = time.Now()
	return
}

type FollowStatus struct {
	FinancialAnalystName string
	Followed             FollowingType
}

func FollowAnalystsByName(userId int, analysts []UserAnalystFollowList, followType FollowingType) (err error) {
	db := models.Main()
	if followType == Following {
		tx := db.Begin()
		for _, analyst := range analysts {
			var dbFollow UserAnalystFollowList
			err = db.Model(&UserAnalystFollowList{}).Where("user_id = ? and financial_analyst_name = ?", userId, analyst.FinancialAnalystName).First(&dbFollow).Error
			if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
				return
			}
			if errors.Is(err, gorm.ErrRecordNotFound) {
				err = db.Create(&analyst).Error
			} else {
				if dbFollow.Followed == Unfollowed {
					analyst.ID = dbFollow.ID
					analyst.CreatedTime = dbFollow.CreatedTime
					analyst.FollowedTime = dbFollow.FollowedTime
					analyst.FollowedTime = time.Now()
					err = db.Updates(&analyst).Error
				}
			}
			if err != nil {
				tx.Rollback()
				return
			}
		}
		tx.Commit()
	}
	if followType == Unfollowed {
		tx := db.Begin()
		for _, analyst := range analysts {
			var dbFollow UserAnalystFollowList
			err = db.Model(&UserAnalystFollowList{}).Where("user_id = ? and financial_analyst_name = ?", userId, analyst.FinancialAnalystName).First(&dbFollow).Error
			if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
				return
			}
			if errors.Is(err, gorm.ErrRecordNotFound) || dbFollow.Followed == Unfollowed {
				continue
			} else {
				analyst.ID = dbFollow.ID
				analyst.CreatedTime = dbFollow.CreatedTime
				analyst.FollowedTime = dbFollow.FollowedTime
				err = db.Updates(&analyst).Error
			}
			if err != nil {
				tx.Rollback()
				return
			}
		}
		tx.Commit()
	}
	if errors.Is(err, gorm.ErrRecordNotFound) {
		err = nil
	}
	return
}
func CheckFollowStatusByNames(userId int, names []string) (result []FollowStatus, err error) {
	db := models.Main()
	var followingList []UserAnalystFollowList
	err = db.Select(FollowingStatusColumns).Where("user_id = ? and followed = ? and financial_analyst_name in ?", userId, Following, names).Find(&followingList).Error
	for _, name := range names {
		result = append(result, FollowStatus{
			FinancialAnalystName: name,
			Followed:             Unfollowed,
		})
	}
	for i := 0; i < len(result); i++ {
		for _, v := range followingList {
			if v.FinancialAnalystName == result[i].FinancialAnalystName {
				result[i].Followed = Following
				break
			}
		}
	}
	return
}
func GetFollowingAnalystList(userId int) (list []UserAnalystFollowList, err error) {
	db := models.Main()
	err = db.Select(listColumns).Where("user_id = ? and followed = ?", userId, Following).Order("followed_time desc").Find(&list).Error
	return
}
func GetFollowing(userId int, analystId int) string {
	db := models.Main()
	var dbFollow UserAnalystFollowList
	err := db.Model(&UserAnalystFollowList{}).Where("user_id = ? and financial_analyst_id = ?", userId, analystId).First(&dbFollow).Error
	if err != nil {
		if !errors.Is(err, gorm.ErrRecordNotFound) {
			logger.Error("查询用户关注状态失败:%v", err)
		}
		return string(Unfollowed)
	}
	return string(dbFollow.Followed)
}
func FollowAnalyst(follow UserAnalystFollowList) (err error) {
	if follow.Followed == "" {
		err = errors.New("关注状态非法")
		return
	}
	db := models.Main()
	var dbFollow UserAnalystFollowList
	err = db.Model(&UserAnalystFollowList{}).Where("user_id = ? and financial_analyst_id = ?", follow.UserID, follow.FinancialAnalystID).First(&dbFollow).Error
	if err != nil {
		if !errors.Is(err, gorm.ErrRecordNotFound) {
			return
		}
		if follow.Followed == Unfollowed {
			return
		}
		err = db.Create(&follow).Error
		return
	}
	if follow.Followed == dbFollow.Followed {
		return
	}
	follow.ID = dbFollow.ID
	follow.CreatedTime = dbFollow.CreatedTime
	follow.FollowedTime = dbFollow.FollowedTime
	if follow.Followed == Following {
		follow.FollowedTime = time.Now()
	}
	err = db.Updates(&follow).Error
	return
}

func GetFollowed(userId int, analystId int) string {
	db := models.Main()
	var record UserAnalystFollowList
	err := db.Model(&UserAnalystFollowList{}).Where("user_id = ? and financial_analyst_id = ?", userId, analystId).Where("followed = ?", Following).First(&record).Error
	if err != nil {
		if !errors.Is(err, gorm.ErrRecordNotFound) {
			logger.Error("查询关注信息失败:%v", err)
		}
		return string(Unfollowed)
	}
	return string(record.Followed)
}
