package user

import (
	"crypto/sha1"
	"fmt"
	"github.com/linmadan/egglib-go/core/application"
	"github.com/tiptok/gocomm/common"
	"github.com/tiptok/gocomm/pkg/log"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/application/factory"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/domain"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/infrastructure/utils"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/protocol"
	protocolx "gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/protocol/user"
	"strings"
	"time"
)

type UserService struct {
}

func (svr *UserService) CreateUser(header *protocol.RequestHeader, request *protocolx.CreateUserRequest) (rsp interface{}, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
	)
	rsp = &protocolx.CreateUserResponse{}
	if err = request.ValidateCommand(); err != nil {
		err = application.ThrowError(application.ARG_ERROR, err.Error())
		return
	}
	if err = transactionContext.StartTransaction(); err != nil {
		err = application.ThrowError(application.TRANSACTION_ERROR, err.Error())
		return
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	newUser := &domain.Users{
		Name:       request.Name,
		Phone:      request.Phone,
		Roles:      request.Roles,
		Status:     1,
		AdminType:  request.AdminType,
		CreateTime: time.Now(),
		UpdateTime: time.Now(),
	}

	var UserRepository, _ = factory.CreateUserRepository(transactionContext)
	if request.Phone != "" {
		if _, err = UserRepository.FindOne(map[string]interface{}{"phone": request.Phone}); err == nil {
			err = protocol.NewCustomMessage(1, "手机号已存在")
			return
		}
	}
	if len(newUser.Passwd) == 0 {
		newUser.Passwd = fmt.Sprintf("%x", sha1.Sum([]byte("123456")))
	}
	if m, e := UserRepository.Save(newUser); e != nil {
		err = application.ThrowError(application.INTERNAL_SERVER_ERROR, e.Error())
		return
	} else {
		rsp = m
	}
	if err = transactionContext.CommitTransaction(); err != nil {
		err = application.ThrowError(application.TRANSACTION_ERROR, err.Error())
		return
	}
	return
}

func (svr *UserService) UpdateUser(header *protocol.RequestHeader, request *protocolx.UpdateUserRequest) (rsp interface{}, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
	)
	rsp = &protocolx.UpdateUserResponse{}
	if err = request.ValidateCommand(); err != nil {
		err = application.ThrowError(application.ARG_ERROR, err.Error())
		return
	}
	if err = transactionContext.StartTransaction(); err != nil {
		log.Error(err)
		return nil, err
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	var UserRepository, _ = factory.CreateUserRepository(transactionContext)
	var user *domain.Users
	if user, err = UserRepository.FindOne(map[string]interface{}{"id": request.Id}); err != nil {
		err = protocol.NewCustomMessage(1, "用户不存在")
		return
	}
	if request.Phone != "" {
		if _, err = UserRepository.FindOne(map[string]interface{}{"phone": request.Phone}); err == nil {
			err = protocol.NewCustomMessage(1, "手机号已存在")
			return
		}
	}
	if err = user.Update(common.ObjectToMap(request)); err != nil {
		err = application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
		return
	}
	if user, err = UserRepository.Save(user); err != nil {
		err = application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
		return
	}
	if err = transactionContext.CommitTransaction(); err != nil {
		err = application.ThrowError(application.TRANSACTION_ERROR, err.Error())
		return
	}
	return
}

func (svr *UserService) GetUser(header *protocol.RequestHeader, request *protocolx.GetUserRequest) (rsp interface{}, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
		RoleRepository, _     = factory.CreateRoleRepository(transactionContext)
	)
	rsp = &protocolx.GetUserResponse{}
	if err = request.ValidateCommand(); err != nil {
		err = application.ThrowError(application.ARG_ERROR, err.Error())
		return
	}
	if err = transactionContext.StartTransaction(); err != nil {
		err = application.ThrowError(application.TRANSACTION_ERROR, err.Error())
		return
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	var UserRepository, _ = factory.CreateUserRepository(transactionContext)
	var user *domain.Users
	if user, err = UserRepository.FindOne(common.ObjectToMap(request)); err != nil {
		err = application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
		return
	}
	retMap := map[string]interface{}{"id": user.Id, "name": user.Name, "phone": user.Phone, "adminType": user.AdminType, "status": user.Status}
	if len(user.Roles) > 0 {
		if _, roles, e := RoleRepository.Find(map[string]interface{}{"inRoleIds": user.Roles}); len(roles) > 0 && e == nil {
			retMap["roles"] = utils.LoadCustomField(roles, "Id", "RoleName")
		}
	}
	rsp = map[string]interface{}{"user": retMap}
	if err = transactionContext.CommitTransaction(); err != nil {
		err = application.ThrowError(application.TRANSACTION_ERROR, err.Error())
		return
	}
	return
}

func (svr *UserService) DeleteUser(header *protocol.RequestHeader, request *protocolx.DeleteUserRequest) (rsp interface{}, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
	)
	rsp = &protocolx.DeleteUserResponse{}
	if err = request.ValidateCommand(); err != nil {
		err = application.ThrowError(application.ARG_ERROR, err.Error())
		return
	}
	if err = transactionContext.StartTransaction(); err != nil {
		err = application.ThrowError(application.TRANSACTION_ERROR, err.Error())
		return
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	var UserRepository, _ = factory.CreateUserRepository(transactionContext)
	var user *domain.Users
	if user, err = UserRepository.FindOne(common.ObjectToMap(request)); err != nil {
		err = application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
		return
	}
	if user, err = UserRepository.Remove(user); err != nil {
		err = application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
		return
	}
	rsp = user
	if err = transactionContext.CommitTransaction(); err != nil {
		err = application.ThrowError(application.TRANSACTION_ERROR, err.Error())
		return
	}
	return
}

func (svr *UserService) ListUser(header *protocol.RequestHeader, request *protocolx.ListUserRequest) (rsp interface{}, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
		RoleRepository, _     = factory.CreateRoleRepository(transactionContext)
	)
	rsp = &protocolx.ListUserResponse{}
	if err = request.ValidateCommand(); err != nil {
		err = application.ThrowError(application.TRANSACTION_ERROR, err.Error())
		return
	}
	if err = transactionContext.StartTransaction(); err != nil {
		log.Error(err)
		return nil, err
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	_, roles, _ := RoleRepository.Find(map[string]interface{}{})
	roleMap := domain.Roles(roles).RoleMap()
	getRoles := func(roleIds []int64) string {
		if len(roleIds) == 0 {
			return ""
		}
		var role []string
		for _, id := range roleIds {
			if v, ok := roleMap[id]; ok {
				role = append(role, v.RoleName)
			}
		}
		return strings.Join(role, ",")
	}

	var UserRepository, _ = factory.CreateUserRepository(transactionContext)
	var user []*domain.Users
	var total int64
	if total, user, err = UserRepository.Find(map[string]interface{}{"offset": (request.PageNumber - 1) * request.PageSize, "limit": request.PageSize, "searchByText": request.SearchByText, "sortById": "DESC"}); err != nil {
		err = application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
		return
	}
	userList := make([]map[string]interface{}, 0)
	for _, v := range user {
		item := map[string]interface{}{"id": v.Id, "name": v.Name, "adminType": v.AdminType, "status": v.Status, "createTime": v.CreateTime.Local().Format("2006-01-02 15:04:05")}
		item["roles"] = getRoles(v.Roles)
		userList = append(userList, item)
	}

	rsp = map[string]interface{}{
		"totalRow":   total,
		"pageNumber": request.PageNumber,
		"list":       userList,
	}
	if err = transactionContext.CommitTransaction(); err != nil {
		err = application.ThrowError(application.TRANSACTION_ERROR, err.Error())
		return
	}
	return
}

func NewUserService(options map[string]interface{}) *UserService {
	svr := &UserService{}
	return svr
}