package user

import (
	"context"
	"server/internal/dao"
	"server/internal/model"
	"server/internal/model/do"
	"server/internal/model/entity"
	"server/internal/service"
	"server/utility/ecode"
	"server/utility/encrypt"
	"server/utility/jwt"
	"strings"

	"github.com/gogf/gf/v2/database/gdb"
)

type sUser struct{}

func New() service.IUser {
	return &sUser{}
}
func init() {
	service.RegisterUser(New())
}

func (s *sUser) Login(ctx context.Context, in *model.UserLoginIn) (out *model.UserLoginOut, err error) {
	user, err := dao.Users.Ctx(ctx).Where(do.Users{Email: in.Email}).One()
	if err != nil {
		return nil, ecode.Fail.Sub("database_query_failed")
	}
	if user == nil {
		return nil, ecode.Auth // 账户名或密码不正确
	}
	var entityUser entity.Users
	if err = user.Struct(&entityUser); err != nil {
		return nil, ecode.Fail.Sub("data_conversion_failed")
	}
	if !encrypt.ComparePassword(entityUser.PasswordHash, in.Password) {
		return nil, ecode.Password // 密码不正确
	}
	// 判断是否为作者
	author, _ := dao.Authors.Ctx(ctx).Where(do.Authors{UserId: entityUser.Id, Status: 1}).One()
	role := "user"
	if author != nil && !author.IsEmpty() {
		role = "author"
	}
	token, err := jwt.GenerateToken(&jwt.TokenIn{UserId: entityUser.Id, Role: role})
	if err != nil {
		return nil, ecode.Fail.Sub("token_generation_failed")
	}
	return &model.UserLoginOut{Token: token}, nil
}

func (s *sUser) Register(ctx context.Context, in *model.UserRegisterIn) (out *model.UserRegisterOut, err error) {
	if in.Password != in.Password2 {
		return nil, ecode.Password.Sub("password_mismatch")
	}
	exist, err := dao.Users.Ctx(ctx).Where(do.Users{Email: in.Email}).Count()
	if err != nil {
		return nil, ecode.Fail.Sub("database_query_failed")
	}
	if exist > 0 {
		return nil, ecode.EmailExist // 该邮箱已被注册
	}
	hash, err := encrypt.EncryptPassword(in.Password)
	if err != nil {
		return nil, ecode.Fail.Sub("password_encryption_failed")
	}
	_, err = dao.Users.Ctx(ctx).Data(do.Users{
		Email:        in.Email,
		PasswordHash: hash,
		Username:     strings.Split(in.Email, "@")[0],
	}).Insert()
	if err != nil {
		return nil, ecode.Fail.Sub("registration_failed")
	}
	return &model.UserRegisterOut{Success: true}, nil
}

func (s *sUser) Info(ctx context.Context, in *model.UserInfoIn) (out *model.UserInfoOut, err error) {
	user, err := dao.Users.Ctx(ctx).Where(do.Users{Id: in.UserId}).One()
	if err != nil {
		return nil, ecode.Fail.Sub("database_query_failed")
	}
	if user == nil {
		return nil, ecode.Auth.Sub("user_not_found")
	}
	var entityUser entity.Users
	if err = user.Struct(&entityUser); err != nil {
		return nil, ecode.Fail.Sub("data_conversion_failed")
	}
	// 查询作者信息
	var authorStatus int
	isAuthor := false
	author, err := dao.Authors.Ctx(ctx).Where(do.Authors{UserId: entityUser.Id}).One()
	if err == nil && !author.IsEmpty() {
		authorStatus = author[dao.Authors.Columns().Status].Int()
		if authorStatus == 1 {
			isAuthor = true
		}
	}
	return &model.UserInfoOut{
		Id:             entityUser.Id,
		Username:       entityUser.Username,
		Email:          entityUser.Email,
		Avatar:         entityUser.Avatar,
		Points:         entityUser.Points, // 如有积分表可补充
		BackgroundUrl:  entityUser.BackgroundUrl,
		AttentionCount: entityUser.AttentionCount,
		IsAuthor:       isAuthor,
		AuthorStatus:   authorStatus,
	}, nil
}

func (s *sUser) Delete(ctx context.Context, in *model.UserDeleteIn) (out *model.UserDeleteOut, err error) {
	// 查询用户信息
	user, err := dao.Users.Ctx(ctx).Where(do.Users{Id: in.UserId}).One()
	if err != nil {
		return nil, ecode.Fail.Sub("database_query_failed")
	}
	if user == nil {
		return nil, ecode.Auth.Sub("user_not_found")
	}

	var entityUser entity.Users
	if err = user.Struct(&entityUser); err != nil {
		return nil, ecode.Fail.Sub("data_conversion_failed")
	}

	// 验证密码
	if !encrypt.ComparePassword(entityUser.PasswordHash, in.Password) {
		return nil, ecode.Password.Sub("password_incorrect")
	}

	// 开启事务，删除用户及相关数据
	err = dao.Users.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		// 1. 删除用户阅读记录
		_, err := dao.UserReadRecords.Ctx(ctx).TX(tx).
			Where(dao.UserReadRecords.Columns().UserId, in.UserId).
			Delete()
		if err != nil {
			return ecode.Fail.Sub("read_record_delete_failed")
		}

		// 2. 删除用户阅读历史
		_, err = dao.UserReadHistory.Ctx(ctx).TX(tx).
			Where(dao.UserReadHistory.Columns().UserId, in.UserId).
			Delete()
		if err != nil {
			return ecode.Fail.Sub("history_delete_failed")
		}

		// 3. 删除用户书架
		_, err = dao.Bookshelves.Ctx(ctx).TX(tx).
			Where(dao.Bookshelves.Columns().UserId, in.UserId).
			Delete()
		if err != nil {
			return ecode.Fail.Sub("bookshelf_delete_failed")
		}

		// 4. 删除用户关注作者记录
		_, err = dao.UserFollowAuthors.Ctx(ctx).TX(tx).
			Where(dao.UserFollowAuthors.Columns().UserId, in.UserId).
			Delete()
		if err != nil {
			return ecode.Fail.Sub("follow_author_delete_failed")
		}

		// 5. 删除用户评分记录
		_, err = dao.BookRatings.Ctx(ctx).TX(tx).
			Where(dao.BookRatings.Columns().UserId, in.UserId).
			Delete()
		if err != nil {
			return ecode.Fail.Sub("rating_delete_failed")
		}

		// 6. 删除用户章节购买记录
		_, err = dao.UserChapterPurchases.Ctx(ctx).TX(tx).
			Where(dao.UserChapterPurchases.Columns().UserId, in.UserId).
			Delete()
		if err != nil {
			return ecode.Fail.Sub("purchase_delete_failed")
		}

		// 7. 删除用户积分日志
		_, err = dao.UserPointsLogs.Ctx(ctx).TX(tx).
			Where(dao.UserPointsLogs.Columns().UserId, in.UserId).
			Delete()
		if err != nil {
			return ecode.Fail.Sub("points_log_delete_failed")
		}

		// 8. 删除用户反馈
		_, err = dao.Feedbacks.Ctx(ctx).TX(tx).
			Where(dao.Feedbacks.Columns().UserId, in.UserId).
			Delete()
		if err != nil {
			return ecode.Fail.Sub("feedback_delete_failed")
		}

		// 9. 删除作者信息（如果用户是作者）
		_, err = dao.Authors.Ctx(ctx).TX(tx).
			Where(dao.Authors.Columns().UserId, in.UserId).
			Delete()
		if err != nil {
			return ecode.Fail.Sub("author_delete_failed")
		}

		// 10. 最后删除用户（软删除）
		_, err = dao.Users.Ctx(ctx).TX(tx).Where(do.Users{Id: in.UserId}).Delete()
		if err != nil {
			return ecode.Fail.Sub("user_delete_failed")
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	return &model.UserDeleteOut{Success: true}, nil
}

func (s *sUser) Code(ctx context.Context, in *model.UserCodeIn) (out *model.UserCodeOut, err error) {
	exist, err := dao.Users.Ctx(ctx).Where(do.Users{Email: in.Email}).Exist()
	if err != nil {
		return nil, ecode.Fail.Sub("database_query_failed")
	}
	if !exist {
		return nil, ecode.Params.Sub("email_not_found")
	}
	return &model.UserCodeOut{Success: true}, nil
}

func (s *sUser) EditPass(ctx context.Context, in *model.UserEditPassIn) (out *model.UserEditPassOut, err error) {
	exist, err := dao.Users.Ctx(ctx).Where(do.Users{Email: in.Email}).Exist()
	if err != nil {
		return nil, ecode.Fail.Sub("database_query_failed")
	}
	if !exist {
		return nil, ecode.Params.Sub("email_not_found")
	}
	if in.Sign != "123456" {
		return nil, ecode.Params.Sub("sign_error")
	}
	if in.Password != in.Password2 {
		return nil, ecode.Password.Sub("password_mismatch")
	}
	hash, err := encrypt.EncryptPassword(in.Password)
	if err != nil {
		return nil, ecode.Fail.Sub("password_encryption_failed")
	}
	_, err = dao.Users.Ctx(ctx).Where(do.Users{Email: in.Email}).Data(do.Users{PasswordHash: hash}).Update()
	if err != nil {
		return nil, ecode.Fail.Sub("password_update_failed")
	}
	return &model.UserEditPassOut{
		Success: true,
	}, nil
}

func (s *sUser) AuthorLogin(ctx context.Context, in *model.UserLoginIn) (out *model.UserLoginOut, err error) {
	user, err := dao.Users.Ctx(ctx).Where(do.Users{Email: in.Email}).One()
	if err != nil {
		return nil, ecode.Fail.Sub("database_query_failed")
	}
	if user == nil {
		return nil, ecode.Auth // 账户名或密码不正确
	}
	var entityUser entity.Users
	if err = user.Struct(&entityUser); err != nil {
		return nil, ecode.Fail.Sub("data_conversion_failed")
	}
	if !encrypt.ComparePassword(entityUser.PasswordHash, in.Password) {
		return nil, ecode.Password // 密码不正确
	}
	// 验证是否为作者
	author, err := dao.Authors.Ctx(ctx).Where(do.Authors{UserId: entityUser.Id, Status: 1}).One()
	if err != nil {
		return nil, ecode.Fail.Sub("author_query_failed")
	}
	if author == nil || author.IsEmpty() {
		return nil, ecode.Auth.Sub("not_author") // 不是作者
	}
	token, err := jwt.GenerateToken(&jwt.TokenIn{UserId: entityUser.Id, Role: "author"})
	if err != nil {
		return nil, ecode.Fail.Sub("token_generation_failed")
	}
	return &model.UserLoginOut{Token: token}, nil
}
