/*
 * @description:项目用户相关数据处理
 * @Author: CP
 * @Date: 2020-08-27 17:23:58
 * @FilePath: \construction_management\services\project_account_service.go
 */
package services

import (
	"encoding/json"
	"errors"
	"html"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/kataras/iris/v12"
	"go.mod/comm"
	"go.mod/lib"
	"go.mod/models"
	"go.mod/web/viewmodels"

	"go.mod/dao"
	"go.mod/datasource"
)

//定义项目用户Service接口
type ProjectAccountService interface {
	ValidRule(ctx iris.Context) (viewmodels.ProjectAccount, error)
	ValidRuleChangePassword(ctx iris.Context) (viewmodels.AccountPassword, error)
	ValidRulePermission(ctx iris.Context) (viewmodels.Permission, error)
	ValidRuleAccount(ctx iris.Context) (viewmodels.ProjectAccount, error)
	ValidGetPermission(ctx iris.Context) (viewmodels.Permission, error)
	ValidRuleProjectId(ctx iris.Context) (viewmodels.ProjectAccount, error)
	Get(accountId int, projectId int) *viewmodels.ProjectAccount
	GetAll(projectId int) []viewmodels.ProjectAccount
	GetBidAccount(bidsectionId int, projectId int, projectAccountId int, name string) []viewmodels.ProjectAccount
	Search(name string, projectId int) []viewmodels.ProjectAccount
	AddBs(viewAccount viewmodels.ProjectAccount, projectId int) error
	SaveBs(viewAccount viewmodels.ProjectAccount, id int, projectId int, staffName string) error
	Add(viewAccount viewmodels.ProjectAccount, projectId int) error
	Save(viewAccount viewmodels.ProjectAccount, id int, projectId int) error
	SaveAccount(viewAccount viewmodels.ProjectAccount, id int, projectId int) error

	SyncAccountBs(projectId int) error

	Enable(id int, projectId int, enable int) error
	ChangeAccount(id int, projectId int, viewAccount viewmodels.ProjectAccount) error
	ChangeAccountBS(id int, projectId int, viewAccount viewmodels.ProjectAccount) error
	GetProjectInfo(id int) (viewmodels.ProjectInfo, error)
	Delete(id int, projectId int) error

	ChangePassword(AccountData viewmodels.AccountPassword, projectId int, projectAccountId int) error

	SaveAuth(permission viewmodels.Permission, projectId int, bidsectionId int, accountId int) error
}

//返回service操作类
type projectAccountService struct {
	dao                  *dao.ProjectAccountDao
	bidAccountDao        *dao.BidAccountDao
	permissionAccountDao *dao.PermissionAccountDao
	projectDao           *dao.ProjectDao
	validSave            string
	validAdd             string
	validPassword        string
}

//创建项目用户service
func NewProjectAccountService() ProjectAccountService {
	return &projectAccountService{
		dao:                  dao.NewProjectAccountDao(datasource.InstanceDbMaster()),
		bidAccountDao:        dao.NewBidAccountDao(datasource.InstanceDbMaster()),
		permissionAccountDao: dao.NewPermissionAccountDao(datasource.InstanceDbMaster()),
		projectDao:           dao.NewProjectDao(datasource.InstanceDbMaster()),
		validSave:            "/api/projectSetting/account/save",
		validAdd:             "/api/projectSetting/account/create",
		validPassword:        "/api/projectSetting/account/change",
	}
}

// 用户规则验证
func (s *projectAccountService) ValidRule(ctx iris.Context) (viewmodels.ProjectAccount, error) {
	accountVaild := viewmodels.ProjectAccount{}
	err := ctx.ReadJSON(&accountVaild)
	if err != nil {
		log.Println("account-ValidRule-ReadForm转换异常, error=", err)
		return accountVaild, err
	}

	if ctx.Path() == s.validAdd {
		err = accountVaild.Validate()
	} else if ctx.Path() == s.validSave {
		err = accountVaild.ValidateUpdate()
	} else if ctx.Path() == s.validPassword {
		err = accountVaild.ValidatePassword()
	} else {
		log.Println("请求路径找不到对应的验证规则")
		return accountVaild, errors.New("验证错误-未找到验证规则")
	}

	if err != nil {
		log.Println("用户验证, error=", err)
		return accountVaild, err
	}

	// 验证账号组
	if ctx.Path() != s.validPassword {
		accountGroup := comm.NewAccountGroup()
		err = accountGroup.ValidRule(accountVaild.AccountGroup)
		if err != nil {
			log.Println("用户验证, error=", err)
			return accountVaild, err
		}
	}
	// xss
	accountVaild.Account = html.EscapeString(accountVaild.Account)
	accountVaild.Password = html.EscapeString(accountVaild.Password)
	accountVaild.Name = html.EscapeString(accountVaild.Name)
	accountVaild.Company = html.EscapeString(accountVaild.Company)
	accountVaild.Position = html.EscapeString(accountVaild.Position)
	accountVaild.Mobile = html.EscapeString(accountVaild.Mobile)
	accountVaild.Telephone = html.EscapeString(accountVaild.Telephone)

	return accountVaild, nil
}

// 验证密码
func (s *projectAccountService) ValidRuleChangePassword(ctx iris.Context) (viewmodels.AccountPassword, error) {
	accountVaild := viewmodels.AccountPassword{}
	err := ctx.ReadJSON(&accountVaild)
	if err != nil {
		log.Println("account-ValidRule-ReadForm转换异常, error=", err)
		return accountVaild, err
	}

	err = accountVaild.ValidateChangePassword()

	if err != nil {
		log.Println("权限验证, error=", err)
		return accountVaild, err
	}

	return accountVaild, nil
}

// 用户规则验证
func (s *projectAccountService) ValidRulePermission(ctx iris.Context) (viewmodels.Permission, error) {
	accountVaild := viewmodels.Permission{}
	err := ctx.ReadJSON(&accountVaild)
	if err != nil {
		log.Println("account-ValidRule-ReadForm转换异常, error=", err)
		return accountVaild, err
	}

	err = accountVaild.Validate()

	if err != nil {
		log.Println("权限验证, error=", err)
		return accountVaild, err
	}

	return accountVaild, nil
}

// 用户规则验证
func (s *projectAccountService) ValidGetPermission(ctx iris.Context) (viewmodels.Permission, error) {
	accountVaild := viewmodels.Permission{}
	err := ctx.ReadForm(&accountVaild)
	if err != nil {
		log.Println("account-ValidRule-ReadForm转换异常, error=", err)
		return accountVaild, err
	}

	err = accountVaild.ValidateSinglePermission()

	if err != nil {
		log.Println("权限验证, error=", err)
		return accountVaild, err
	}

	return accountVaild, nil
}

// 验证编辑用户
func (s *projectAccountService) ValidRuleAccount(ctx iris.Context) (viewmodels.ProjectAccount, error) {
	accountVaild := viewmodels.ProjectAccount{}
	err := ctx.ReadJSON(&accountVaild)
	if err != nil {
		log.Println("account-ValidRule-ReadForm转换异常, error=", err)
		return accountVaild, err
	}

	err = accountVaild.ValidateAccount()

	if err != nil {
		log.Println("权限验证, error=", err)
		return accountVaild, err
	}

	return accountVaild, nil
}

// 验证用户项目ID
func (s *projectAccountService) ValidRuleProjectId(ctx iris.Context) (viewmodels.ProjectAccount, error) {
	accountVaild := viewmodels.ProjectAccount{}
	err := ctx.ReadForm(&accountVaild)
	if err != nil {
		log.Println("account-ValidRule-ReadForm转换异常, error=", err)
		return accountVaild, err
	}

	err = accountVaild.ValidateProjectId()

	if err != nil {
		log.Println("权限验证, error=", err)
		return accountVaild, err
	}

	return accountVaild, nil
}

// 获得一个项目用户
func (s *projectAccountService) Get(id int, projectId int) *viewmodels.ProjectAccount {
	modelsAccount := s.dao.Get(id, projectId)
	viewAccountData := viewmodels.ProjectAccount{}
	if modelsAccount.Id == 0 {
		viewAccountData.Id = "0"
		return &viewAccountData
	}

	viewAccountData = comm.MakeProjectAccountVM(modelsAccount)
	return &viewAccountData
}

// 获得项目下所有账号信息
func (s *projectAccountService) GetAll(projectId int) []viewmodels.ProjectAccount {
	accountList := s.dao.GetAll(projectId)
	accountListVM := make([]viewmodels.ProjectAccount, 0)
	for _, data := range accountList {
		//if data.IsAdmin != 1 {
		account := comm.MakeProjectAccountVM(&data)

		accountListVM = append(accountListVM, account)
		//}
	}
	return accountListVM
}

// 获得标段下的账号
func (s *projectAccountService) GetBidAccount(bidsectionId int, projectId int, projectAccountId int, name string) []viewmodels.ProjectAccount {
	// 1.获得标段账号ID
	bidAccountData := s.bidAccountDao.GetBidAccount(bidsectionId, projectId)

	// 组合账号ID集合
	idList := []string{}
	// 管理员账号-可能不必要-加入管理员ID
	projectDao := dao.NewProjectDao(datasource.InstanceDbMaster())
	projectData := projectDao.Get(projectId)
	idList = append(idList, strconv.Itoa(projectData.UserId))

	for _, item := range bidAccountData {
		idList = append(idList, strconv.Itoa(item.AccountId))
	}
	inId := strings.Join(idList, ",")

	// 获得账号信息
	accountData := s.dao.GetInId(inId, name)

	// 2.获得账号权限
	permissionData := s.permissionAccountDao.GetBidsectionId(bidsectionId)

	// 格式化账号数据
	accountListVM := make([]viewmodels.ProjectAccount, 0)
	for _, data := range accountData {
		account := comm.MakeProjectAccountVM(&data)
		for _, item := range permissionData {
			if data.Id == item.AccountId {
				account.ContractPermission = item.ContractPermission
				account.QualityPermission = item.QualityPermission
				account.SafePermission = item.SafePermission
				break
			}
		}
		accountListVM = append(accountListVM, account)
	}

	return accountListVM
}

// 检索 账号姓名单位手机
func (s *projectAccountService) Search(name string, projectId int) []viewmodels.ProjectAccount {
	accountList := s.dao.Search(name, projectId)
	accountListVM := make([]viewmodels.ProjectAccount, 0)
	for _, data := range accountList {
		account := comm.MakeProjectAccountVM(&data)
		accountListVM = append(accountListVM, account)
	}
	return accountListVM
}

// 新增账号-后台
func (s *projectAccountService) AddBs(viewAccount viewmodels.ProjectAccount, projectId int) error {

	// 验证该项目下是否有同名账号
	// accountValid := s.dao.GetAccount(viewAccount.Account)
	accountValid := s.dao.GetAccountProjectId(viewAccount.Account, projectId)
	if accountValid.Id != 0 {
		return errors.New("项目下已存在相同的账号")
	}

	account := models.CmProjectAccount{}

	if viewAccount.BoolAdmin {
		account.IsAdmin = 1

		if err := s.updateAdminZero(projectId); err != nil {
			return err
		}
	}

	account.ProjectId = projectId
	account.Account = viewAccount.Account
	account.Password = comm.CreatePasswordSign(viewAccount.Password, viewAccount.Account)
	account.AccountGroup = viewAccount.AccountGroup
	account.Name = viewAccount.Name
	account.Company = viewAccount.Company
	account.Position = viewAccount.Position
	account.Mobile = viewAccount.Mobile
	account.Telephone = viewAccount.Telephone
	account.Enable = 1
	account.CreateTime = time.Now()
	err := s.dao.Add(&account)

	// 同步更新项目管理员信息
	projectDao := dao.NewProjectDao(datasource.InstanceDbMaster())
	project := &models.CmProject{}
	project.Id = projectId
	project.UserId = account.Id
	project.UserAccount = viewAccount.Name

	if err := projectDao.Update(project, []string{"user_id", "user_account"}); err != nil {
		return err
	}

	return err
}

// 保存用户信息
func (s *projectAccountService) SaveBs(viewAccount viewmodels.ProjectAccount, id int, projectId int, staffName string) error {

	// 1.获得项目信息
	projectDao := dao.NewProjectDao(datasource.InstanceDbMaster())
	// projectData, _ := projectDao.FindById(projectId)
	// if staffName != projectData.StaffName {
	// 	return errors.New("无权编辑")
	// }

	account := models.CmProjectAccount{}
	updateField := []string{"name", "company", "position", "telephone", "account_group"}

	// 是否重新设置管理员
	if viewAccount.BoolAdmin {
		account.IsAdmin = 1
		updateField = append(updateField, "is_admin")

		// 1.更新项目管理员信息
		project := &models.CmProject{}
		project.Id = projectId
		project.UserId = id
		project.UserAccount = viewAccount.Name

		if err := projectDao.Update(project, []string{"user_id", "user_account"}); err != nil {
			return err
		}

		// 去除其他账号的管理员
		if err := s.updateAdminZero(projectId); err != nil {
			return err
		}
	}

	account.Id = id
	account.ProjectId = projectId
	account.Name = viewAccount.Name
	account.Company = viewAccount.Company
	account.Position = viewAccount.Position
	account.Mobile = viewAccount.Mobile
	account.Telephone = viewAccount.Telephone
	account.AccountGroup = viewAccount.AccountGroup

	err := s.dao.Update(&account, updateField)

	return err
}

// 同步账号后台
func (s *projectAccountService) SyncAccountBs(projectId int) error {
	var (
		accountList []map[string]interface{}
		err         error
	)
	// 1.先获得项目信息
	projectData := s.projectDao.Get(projectId)
	if projectData.Id == 0 {
		return errors.New("项目不存在")
	}

	// 获得计量
	Jlzf := lib.NewJlzf()
	if accountList, err = Jlzf.GetAccountList(projectData.Code); err != nil {
		return err
	}

	if err = s.dao.JlSync(accountList, projectId); err != nil {
		return err
	}

	return nil
}

// 设置is_admin为0
func (s *projectAccountService) updateAdminZero(projectId int) error {
	dataDao := s.dao.GetAdmin(projectId)
	if dataDao.Id != 0 {
		updateData := models.CmProjectAccount{}
		updateData.Id = dataDao.Id
		updateData.ProjectId = projectId
		updateData.IsAdmin = 0
		if err := s.dao.Update(&updateData, []string{"is_admin"}); err != nil {
			return errors.New("原管理员取消失败")
		}
	}
	return nil
}

// 新增账号
func (s *projectAccountService) Add(viewAccount viewmodels.ProjectAccount, projectId int) error {

	// 验证该项目下是否有同名账号
	accountValid := s.dao.GetAccountProjectId(viewAccount.Account, projectId)
	if accountValid.Id != 0 {
		return errors.New("已存在相同的账号")
	}

	account := models.CmProjectAccount{}
	account.ProjectId = projectId
	account.Account = viewAccount.Account
	account.Password = comm.CreatePasswordSign(viewAccount.Password, viewAccount.Account)
	account.Name = viewAccount.Name
	account.Company = viewAccount.Company
	account.Position = viewAccount.Position
	account.Mobile = viewAccount.Mobile
	account.Telephone = viewAccount.Telephone
	account.AccountGroup = viewAccount.AccountGroup
	account.Enable = 1
	account.CreateTime = time.Now()
	err := s.dao.Add(&account)
	return err
}

// 保存用户信息
func (s *projectAccountService) Save(viewAccount viewmodels.ProjectAccount, id int, projectId int) error {

	account := models.CmProjectAccount{}
	account.Id = id
	account.ProjectId = projectId
	account.Name = viewAccount.Name
	account.Company = viewAccount.Company
	account.Position = viewAccount.Position
	account.Mobile = viewAccount.Mobile
	account.Telephone = viewAccount.Telephone
	account.AccountGroup = viewAccount.AccountGroup

	err := s.dao.Update(&account, []string{"Name", "Company", "Position", "Telephone", "AccountGroup"})

	return err
}

func (s *projectAccountService) SaveAccount(viewAccount viewmodels.ProjectAccount, id int, projectId int) error {
	account := models.CmProjectAccount{}
	account.Id = id
	account.ProjectId = projectId
	account.Name = viewAccount.Name
	account.Company = viewAccount.Company
	account.Position = viewAccount.Position
	account.Telephone = viewAccount.Telephone
	err := s.dao.Update(&account, []string{"Name", "Company", "Position", "Telephone"})

	return err
}

// 设置启用/禁止
func (s *projectAccountService) Enable(id int, projectId int, enable int) error {

	account := models.CmProjectAccount{}
	account.Id = id
	account.ProjectId = projectId
	account.Enable = enable
	err := s.dao.Update(&account, []string{"Enable"})

	return err
}

// 删除账号
func (s *projectAccountService) Delete(id int, projectId int) error {
	account := models.CmProjectAccount{}
	account.Id = id
	account.ProjectId = projectId
	err := s.dao.Delete(&account)

	return err
}

// 更改账号或者密码
func (s *projectAccountService) ChangeAccount(id int, projectId int, viewAccount viewmodels.ProjectAccount) error {
	// 1.是否修改账号
	field := []string{"Password"}
	account := models.CmProjectAccount{}
	account.Id = id
	account.ProjectId = projectId

	// 2.修改密码
	account.Password = comm.CreatePasswordSign(viewAccount.Password, viewAccount.Account)

	accountData := s.dao.Get(id, projectId)
	if accountData.Account != viewAccount.Account {
		account.Account = viewAccount.Account
		field = append(field, "Account")
	}

	// 3.发送短信-TODO
	// utils.SendSMS()

	s.dao.Update(&account, field)

	return nil
}

// 更改账号或者密码-后台
func (s *projectAccountService) ChangeAccountBS(id int, projectId int, viewAccount viewmodels.ProjectAccount) error {
	// 1.是否修改账号
	field := []string{"Password"}
	account := models.CmProjectAccount{}
	account.Id = id
	account.ProjectId = projectId

	// 2.修改密码
	account.Password = comm.CreatePasswordSign(viewAccount.Password, viewAccount.Account)

	accountData := s.dao.Get(id, projectId)
	if accountData.Account != viewAccount.Account {
		account.Account = viewAccount.Account
		field = append(field, "Account")
	}

	s.dao.Update(&account, field)

	return nil
}

// 更换密码
func (s *projectAccountService) ChangePassword(AccountData viewmodels.AccountPassword, projectId int, projectAccountId int) error {
	// 1.获得账号
	accountData := s.dao.Get(projectAccountId, projectId)
	// 2.比对密码
	password := comm.CreatePasswordSign(AccountData.Password, accountData.Account)

	if accountData.Password == "JL" {
		return errors.New("计量密码不允许修改密码")
	}

	if accountData.Password != password {
		return errors.New("原密码输入不正确")
	}

	// 3修改密码
	field := []string{"Password"}
	account := models.CmProjectAccount{}
	account.Id = projectAccountId
	account.ProjectId = projectId
	account.Password = comm.CreatePasswordSign(AccountData.NewPassword, accountData.Account)

	err := s.dao.Update(&account, field)
	if err != nil {
		return errors.New("密码更新失败")
	}
	return nil
}

func (s *projectAccountService) GetProjectInfo(id int) (viewmodels.ProjectInfo, error) {
	projectInfo, err := s.dao.FindById(id)

	return projectInfo, err
}

// 保存权限设置
func (s *projectAccountService) SaveAuth(permission viewmodels.Permission, projectId int, bidsectionId int, accountId int) error {
	// 1.构造权限字符串
	// 1-1.合同权限
	contractPermission := map[string]int{
		"add":    permission.ContractAdd,
		"delete": permission.ContractDelete,
		"access": permission.ContractAccess,
	}
	contractPermissionByte, err := json.Marshal(contractPermission)
	if err != nil {
		return errors.New("合同权限解析失败")
	}
	contractPermissionStr := string(contractPermissionByte)
	// 1.2 安全巡检权限
	safePermission := map[string]int{
		"add":    permission.SafeAdd,
		"delete": permission.SafeDelete,
		"access": permission.SafeAccess,
	}
	safePermissionByte, err := json.Marshal(safePermission)
	if err != nil {
		return errors.New("合同权限解析失败")
	}
	safePermissionStr := string(safePermissionByte)
	// 1.3 质量巡检权限
	qualityPermission := map[string]int{
		"add":    permission.QualityAdd,
		"delete": permission.QualityDelete,
		"access": permission.QualityAccess,
	}
	qualityPermissionByte, err := json.Marshal(qualityPermission)
	if err != nil {
		return errors.New("合同权限解析失败")
	}
	qualityPermissionStr := string(qualityPermissionByte)

	// 2.保存权限
	permissionAccount := models.CmPermissionAccount{}
	permissionAccount.ProjectId = projectId
	permissionAccount.BidsectionId = bidsectionId
	permissionAccount.AccountId = accountId
	permissionAccount.ContractPermission = contractPermissionStr
	permissionAccount.SafePermission = safePermissionStr
	permissionAccount.QualityPermission = qualityPermissionStr

	err = s.permissionAccountDao.Update(&permissionAccount, []string{"ContractPermission", "SafePermission", "QualityPermission"})
	return err
}
