/*
 * @description: 计量业务相关
 * @Author: CP
 * @Date: 2021-12-25 14:37:01
 * @FilePath: \construction_management\services\jl_service.go
 */
package services

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/dgrijalva/jwt-go"
	"go.mod/comm"
	"go.mod/conf"
	"go.mod/dao"
	"go.mod/datasource"
	"go.mod/lib"
	"go.mod/models"
	"go.mod/web/utils"
	"go.mod/web/viewmodels"
)

type JlService struct {
	dao             *dao.ProjectDao
	accountDao      *dao.ProjectAccountDao
	treeContractDao *dao.TreeContractDao
	contractDao     *dao.ContractDao
}

// 创建项目用户service
func NewJlService() *JlService {
	return &JlService{
		dao:             dao.NewProjectDao(datasource.InstanceDbMaster()),
		accountDao:      dao.NewProjectAccountDao(datasource.InstanceDbMaster()),
		treeContractDao: dao.NewTreeContractDao(datasource.InstanceDbMaster()),
		contractDao:     dao.NewContractDao(datasource.InstanceDbMaster()),
	}
}

// 根据表名获得相关数据
func (s *JlService) GetTableInfo(data *viewmodels.Jl, projectId int) map[string]interface{} {
	bids := strings.Replace(strings.Trim(fmt.Sprint(data.BidsectionId), "[]"), " ", ",", -1)
	result := map[string]interface{}{}

	for _, v := range data.Key {
		// 获得标段下，合同树
		if v == "tree_contracts" {
			result["tree_contracts"] = s.treeContractDao.GetByProjectIdInBidsectionId(bids, projectId)
		} else if v == "contracts" {
			result["contracts"] = s.contractDao.GetByProjectIdInBidsectionId(bids, projectId)
		}
	}
	return result
}

// 是否有项目
func (s *JlService) IsCode(code string) map[string]interface{} {
	exist := 0
	if code != "" {
		projectData := s.dao.GetCode(code)
		if projectData.Id != 0 {
			exist = 1
		}
	}

	data := map[string]interface{}{
		"exist": exist,
	}

	return data
}

// 从计量 创建 项目和管理员账号
func (s *JlService) ProjectAdd(claimsData *viewmodels.Jl) (map[string]interface{}, error) {

	var (
		err             error
		JlResultProject map[string]interface{}
		JlResultAccount map[string]interface{}
		accountData     *models.CmProjectAccount
	)

	Jlzf := lib.NewJlzf()
	// 1.获得计量 账号和项目 信息
	if JlResultProject, JlResultAccount, err = Jlzf.GetProjectAndAccount(claimsData.Code, claimsData.Account); err != nil {
		return nil, err
	}
	accountGroup := int(JlResultAccount["accountGroup"].(float64))

	// fmt.Println(JlResultProject)
	// fmt.Println(JlResultAccount)
	// 2. 计量账号 是否是管理员
	// 管理员 --只能管理员才能创建项目
	if JlResultAccount["isAdmin"].(float64) == 1 {
		// 2-1. 获得本地项目
		projectData := s.dao.GetCode(claimsData.Code)
		// 2-1-1.项目不存在(账号肯定不存在) - 创建项目
		if projectData.Id == 0 {
			//组合数据-项目 - 标注授权开启互通
			categoryId := strconv.FormatFloat(JlResultProject["categoryId"].(float64), 'f', 0, 64)

			project := &models.CmProject{}
			project.Name = JlResultProject["name"].(string)
			project.Code = JlResultProject["code"].(string)

			project.StaffName = JlResultProject["staff"].(string)

			project.CategoryId = categoryId
			project.Category = JlResultProject["category"].(string)
			project.InsideCategoryid = categoryId
			project.InsideCategory = JlResultProject["category"].(string)
			project.CreateTime = time.Now()
			project.CreateName = "计量授权创建"
			project.JlReciprocate = 1
			project.Status = 1

			//组合数据-账号 - 标注 计量授权账号-设置为管理员
			account := &models.CmProjectAccount{}
			account.Account = JlResultAccount["account"].(string)
			account.Password = "JL"
			account.AccountGroup = accountGroup
			account.Name = JlResultAccount["name"].(string)
			account.Company = JlResultAccount["company"].(string)
			account.Position = JlResultAccount["role"].(string)
			account.Mobile = JlResultAccount["mobile"].(string)
			account.Telephone = JlResultAccount["telephone"].(string)
			account.Enable = 1
			account.IsAdmin = 1
			account.CreateTime = time.Now()
			account.JlAuth = 1

			// 创建项目和账号
			if err = s.dao.AddProjectAndAccount(project, account); err != nil {
				return nil, err
			}

		} else {
			// 1.需要开启互通
			project := &models.CmProject{}
			project.JlReciprocate = 1
			project.Id = projectData.Id
			if err := s.dao.Update(project, []string{"jl_reciprocate"}); err != nil {
				return nil, err
			}

			// 计量授权账号
			account := &models.CmProjectAccount{}
			account.JlAuth = 1
			// 1-2. 获得账号-计量账号在项目管理中
			accountData = s.accountDao.GetAccountProjectId(claimsData.Account, projectData.Id)
			// 1-3. 不存在
			if accountData.Id == 0 {
				// 管理员-是否存在 ——需求还不明确，是否要设置成管理员 -先不做 ——NOTODO
				// adminAccount := s.accountDao.GetAdmin(projectData.Id)
				// 管理员不存在设置管理员
				// if adminAccount.Id == 0 {
				// 	account.IsAdmin = 1
				// }
				account.ProjectId = projectData.Id
				account.Account = JlResultAccount["account"].(string)
				account.Password = "JL"
				account.AccountGroup = accountGroup
				account.Name = JlResultAccount["name"].(string)
				account.Company = JlResultAccount["company"].(string)
				account.Position = JlResultAccount["role"].(string)
				account.Mobile = JlResultAccount["mobile"].(string)
				account.Telephone = JlResultAccount["telephone"].(string)
				account.Enable = 1
				account.CreateTime = time.Now()
				if err := s.accountDao.Add(account); err != nil {
					return nil, err
				}
			} else {
				// 存在
				account.Id = accountData.Id
				if err := s.accountDao.Update(account, []string{"jl_auth"}); err != nil {
					return nil, err
				}
			}

		}
	} else {
		//2-2. 普通账号
		return nil, errors.New("只能由 管理员 创建 项目管理项目")
	}

	// 返回一个token 6秒
	tokenString, _ := utils.CreateJlToken(jwt.MapClaims{
		"data": map[string]string{"code": claimsData.Code, "account": claimsData.Account},
		"exp":  time.Now().Add(9 * time.Second).Unix(),
	})
	log.Println("登陆验证,=", tokenString)

	return map[string]interface{}{"token": tokenString}, nil
}

// 授权登陆
func (s *JlService) AuthLogin(claimsData *viewmodels.Jl, writer http.ResponseWriter) (*viewmodels.ProjectAccount, error) {

	var (
		err error
		// JlResultProject map[string]interface{}
		JlResultAccount map[string]interface{}
	)

	// 1-1.工程项目是否存在
	projectInfo := s.dao.GetCode(claimsData.Code)

	if projectInfo.Id == 0 {
		return nil, errors.New("工程建设管理员还未创建项目，禁止登录")
	}
	if projectInfo.Status == 0 {
		return nil, errors.New("项目被禁用，请联系管理员开启")
	}
	// // 1-2.获得项目管理员- 授权登陆不需要验证管理员
	// projectAdminInfo := s.accountDao.Get(projectInfo.UserId, projectInfo.Id)
	// if projectAdminInfo.Id == 0 {
	// 	return nil, errors.New("工程建设管理员不存在，禁止登录")
	// }

	// 计量 的 项目下 是否存在 账号
	Jlzf := lib.NewJlzf()
	// 1.获得计量 账号和项目 信息 - 表示验证通过
	if _, JlResultAccount, err = Jlzf.GetProjectAndAccount(claimsData.Code, claimsData.Account); err != nil {
		return nil, errors.New("计量 校验失败-未找到项目或账号")
	}

	// 2.验证登陆-临时
	projectAccountInfo := s.accountDao.GetAccountProjectId(claimsData.Account, projectInfo.Id)
	account := &models.CmProjectAccount{}
	account.JlAuth = 1
	// 本地没有账号
	if projectAccountInfo.Id == 0 {
		accountGroup := int(JlResultAccount["accountGroup"].(float64))
		account.ProjectId = projectInfo.Id
		account.Account = JlResultAccount["account"].(string)
		account.Password = "JL"
		account.AccountGroup = accountGroup
		account.Name = JlResultAccount["name"].(string)
		account.Company = JlResultAccount["company"].(string)
		account.Position = JlResultAccount["role"].(string)
		account.Mobile = JlResultAccount["mobile"].(string)
		account.Telephone = JlResultAccount["telephone"].(string)
		account.Enable = 1
		account.CreateTime = time.Now()
		if err := s.accountDao.Add(account); err != nil {
			return nil, err
		}
		// 覆盖原来的信息
		projectAccountInfo = account
	} else if projectAccountInfo.JlAuth == 0 {
		// 更新为互通授权账号
		account.Id = projectAccountInfo.Id
		if err := s.accountDao.Update(account, []string{"jl_auth"}); err != nil {
			return nil, err
		}
	}
	// 2-1.账号停用
	if projectAccountInfo.Enable == 0 {
		return nil, errors.New("该账号已被停用")
	}

	// 加密用户标识
	identity, err := comm.AesEncrypt(strconv.Itoa(projectAccountInfo.Id), conf.CookieSecret)
	if err != nil {
		return nil, err
	}
	// 加密项目标识
	projectId, err := comm.AesEncrypt(strconv.Itoa(projectAccountInfo.ProjectId), conf.CookieSecret)
	if err != nil {
		return nil, err
	}

	digitalToken := comm.CreateSign(conf.CookieSecret + strconv.Itoa(projectAccountInfo.Id))

	// 设置cookie
	maxAge := 60 * 60 * 24 * 7
	params := url.Values{}
	params.Add("identity", identity)
	params.Add("attachedIdentity", projectId)
	params.Add("digitalToken", digitalToken)
	c := &http.Cookie{
		Name:     "cm",
		Value:    params.Encode(),
		Path:     "/",
		MaxAge:   maxAge,
		HttpOnly: true,
	}
	http.SetCookie(writer, c)

	viewAccountData := comm.MakeProjectAccountVM(projectAccountInfo)

	return &viewAccountData, nil
}

// 项目存在
func (s *JlService) ProjectExist(projectId int, accountId int) (map[string]interface{}, error) {

	projectData := s.dao.Get(projectId)
	if projectData.Id == 0 {
		return nil, errors.New("项目未找到")
	}
	if projectData.JlReciprocate != 1 {
		return nil, errors.New("计量未开通 跳转")
	}
	accountData := s.accountDao.Get(accountId, projectId)
	if accountData.Id == 0 {
		return nil, errors.New("账号未找到")
	}
	if accountData.JlAuth != 1 {
		return nil, errors.New("计量未开通 此账号 跳转")
	}

	// 计量 的 项目下 是否存在 账号
	Jlzf := lib.NewJlzf()
	// 1.获得计量 账号和项目 信息 - 表示验证通过
	if _, _, err := Jlzf.GetProjectAndAccount(projectData.Code, accountData.Account); err != nil {
		return nil, errors.New("计量 校验失败-未找到项目或账号")
	}

	debug := utils.GetEnvInfo("DEBUG")
	expirationTime := time.Now().Add(6 * time.Second)
	tokenString, _ := utils.CreateJlToken(jwt.MapClaims{
		"data": map[string]string{"code": projectData.Code, "account": accountData.Account},
		"exp":  expirationTime.Unix(),
		"iat":  time.Now().Unix(),
	})
	if debug == "" {
		debug = "prod"
	}

	return map[string]interface{}{"env": debug, "token": tokenString}, nil
}

// 项目存在
func (s *JlService) AccountUpdate(claimsData *viewmodels.Jl) error {

	// 1-1.工程项目是否存在
	projectInfo := s.dao.GetCode(claimsData.Code)
	if projectInfo.Id == 0 {
		return errors.New("项目未找到")
	}

	newAccountData := s.accountDao.GetAccountProjectId(claimsData.NewAccount, projectInfo.Id)
	if newAccountData.Id != 0 {
		return errors.New("项目管理 已存在该账号")
	}

	//
	accountData := s.accountDao.GetAccountByAuth(claimsData.Account, projectInfo.Id)
	fmt.Println(claimsData)
	fmt.Println(accountData)
	if accountData.Id == 0 {
		return errors.New("未找到该项目下的 授权账号")
	}

	account := models.CmProjectAccount{}
	updateField := []string{"account"}

	account.Id = accountData.Id
	account.ProjectId = projectInfo.Id
	account.Account = claimsData.NewAccount
	if err := s.accountDao.Update(&account, updateField); err != nil {
		return err
	}
	return nil
}
