package services

import (
	"errors"
	"fmt"
	"log"
	"strconv"
	"time"

	"go.mod/comm"
	"go.mod/conf"
	"go.mod/lib"
	"go.mod/models"
	"go.mod/web/utils"
	"go.mod/web/viewmodels"
)

// 获得合同项目节
func (s *contractService) GetSecionTree(bidsectionId int, projectId int, treeType int) *viewmodels.TreeSectionContract {
	dataList := s.treeContractDao.GetAll(bidsectionId, projectId, treeType)
	sectionList := s.makeSectionTreeView(dataList)

	// Node := sectionRoot //父节点
	Node := sectionList[0] //父节点
	comm.MakeSectionContract(sectionList, Node)
	return Node
}

// 获得项目节树和孩子们下的合同数据
func (s *contractService) GetSectionTreeContract(attribution string, bidsectionId int, projectId int, treeType int) []*viewmodels.Contracts {
	s.treeContractDao.GetAttribution(attribution, bidsectionId, projectId, treeType)
	return nil
}

// 设置合同项目节初始数据-根据模板导入
func (s *contractService) SetSection(templateNumber int, bidsectionId int, projectId int, treeType int) error {
	// 获得模板数据
	templateTree := make([]*lib.ItemSectionTemplateTree, 0)
	if templateNumber == 1 {
		templateTree = lib.NewItemSectionData().TemplateList1
	} else if templateNumber == 2 {
		templateTree = lib.NewItemSectionData().TemplateList2
	} else {
		return errors.New("找不到合同项目节模板")
	}

	// 1.组合数据-写入库中
	sectionTreeList := make([]*models.CmTreeContracts, 0)
	for _, item := range templateTree {
		section := &models.CmTreeContracts{}
		section.TreeId = item.Id
		section.TreeType = treeType
		section.ParentId = item.ParentId
		section.ProjectId = projectId
		section.BidsectionId = bidsectionId
		section.Name = item.Name
		section.Depth = item.Depth
		section.Serial = item.Serial
		section.Attribution = item.Attribution
		section.Code = fmt.Sprintf("%s%d", item.Attribution, item.Serial)
		section.CreateTime = time.Now()

		section.ContractPrice = "0"
		section.ContractReturned = "0"
		section.ContractsPaid = "0"

		sectionTreeList = append(sectionTreeList, section)
	}

	err := s.treeContractDao.CreateAll(sectionTreeList)
	if err != nil {
		log.Println("设置合同项目节模板错误 err=", err)
		return errors.New("设置合同项目节模板错误")
	}
	return nil
}

// 新增项目节
func (s *contractService) SectionAdd(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) error {
	// 1.验证项目节ID
	treeId, err := utils.GetDecryptId(sectionData.Id)
	if err != nil {
		return err
	}
	sectionFather := s.treeContractDao.Get(treeId, bidsectionId, projectId, treeType)
	if sectionFather.Id == 0 {
		return errors.New("未找到合同项目节")
	}
	// 1-1 深度为>=2才能新增项目节
	// if sectionFather.Depth < 3 {
	// 	return errors.New("请在项目节第三层开始编辑")
	// }
	// 1-2 项目节是否有合同
	if sectionFather.ContractId != 0 {
		return errors.New("该项目节已存在合同")
	}

	// 2 获得最大序号
	// 2-1 孩子节点
	childrenList := s.treeContractDao.GetChildren(treeId, bidsectionId, projectId, treeType)
	// 2-1 最大序号
	serial := 1
	if len(childrenList) != 0 {
		serial = childrenList[len(childrenList)-1].Serial + 1
	}
	// 2-2 归属
	attribution := fmt.Sprintf("%s%d-", sectionFather.Attribution, sectionFather.Serial)
	code := fmt.Sprintf("%s%d", attribution, serial)
	// 新增项目节
	sectionCM := &models.CmTreeContracts{}
	sectionCM.TreeId = treeType
	sectionCM.ParentId = sectionFather.TreeId
	sectionCM.Name = sectionData.Name
	sectionCM.Depth = sectionFather.Depth + 1
	sectionCM.Serial = serial
	sectionCM.Attribution = attribution
	sectionCM.Code = code

	sectionCM.ProjectId = projectId
	sectionCM.BidsectionId = bidsectionId
	sectionCM.ContractPrice = "0"
	sectionCM.ContractReturned = "0"
	sectionCM.ContractsPaid = "0"

	err = s.treeContractDao.Create(sectionCM)
	if err != nil {
		return err
	}
	return nil
}

// 保存名称
func (s *contractService) SectionSave(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) error {
	// 1.验证项目节ID
	treeId, err := utils.GetDecryptId(sectionData.Id)
	if err != nil {
		return err
	}
	section := s.treeContractDao.Get(treeId, bidsectionId, projectId, treeType)
	if section.Id == 0 {
		return errors.New("未找到合同项目节")
	}

	// 1-1 深度为>=2才能新增项目节
	// if section.Depth < 2 {
	// 	return errors.New("请在项目节第三层开始编辑")
	// }

	// 2.保存
	sectionCM := &models.CmTreeContracts{}
	sectionCM.Name = sectionData.Name
	sectionCM.Id = section.Id

	err = s.treeContractDao.Save(sectionCM, []string{"Name"})
	if err != nil {
		return errors.New("保存失败")
	}
	return nil
}

// 更新序号
func (s *contractService) UpdateSerial(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) error {
	// 1.验证项目节ID
	treeId, err := utils.GetDecryptId(sectionData.Id)
	if err != nil {
		return err
	}
	section := s.treeContractDao.Get(treeId, bidsectionId, projectId, treeType)
	if section.Id == 0 {
		return errors.New("未找到合同项目节")
	}

	// 1-1 深度为>=2才能新增项目节
	// if section.Depth < 2 {
	// 	return errors.New("请在项目节第三层开始编辑")
	// }

	err = s.treeContractDao.UpdateSerial(section, sectionData.Serial, treeType)
	if err != nil {
		return errors.New("更新失败")
	}
	return nil
}

// 项目节删除
func (s *contractService) SectionDelete(treeId int, bidsectionId int, projectId int, treeType int) error {
	// 1.验证项目节ID
	section := s.treeContractDao.Get(treeId, bidsectionId, projectId, treeType)
	if section.Id == 0 {
		return errors.New("未找到合同项目节")
	}

	// 1-1 深度为>=2才能新增项目节
	// if section.Depth < 2 {
	// 	return errors.New("请在项目节第三层开始编辑")
	// }
	// 1-2 有合同的不能编辑(包含孩子节点)
	contractList := s.GetSectionTreeContract(section.Attribution, section.BidsectionId, section.ProjectId, treeType)
	if len(contractList) != 0 {
		return errors.New("该项目节存在合同")
	}

	err := s.treeContractDao.Delete(section)
	if err != nil {
		return err
	}
	return nil
}

// 项目节的层级移动
func (s *contractService) MoveDepth(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) error {
	// 1.验证项目节ID
	treeId, err := utils.GetDecryptId(sectionData.Id)
	if err != nil {
		return err
	}
	section := s.treeContractDao.Get(treeId, bidsectionId, projectId, treeType)
	if section.Id == 0 {
		return errors.New("未找到合同项目节")
	}
	// 1-1 深度为>=2才能新增项目节
	// if section.Depth < 2 {
	// 	return errors.New("请在项目节第三层开始编辑")
	// }
	// 1-2 有合同的不能编辑(包含孩子节点)
	contractList := s.GetSectionTreeContract(section.Attribution, section.BidsectionId, section.ProjectId, treeType)
	if len(contractList) != 0 {
		return errors.New("该项目节已存在合同")
	}

	// 2.层级降级-同级有前一个兄弟节点
	elderBrother := &models.CmTreeContracts{}
	if sectionData.Operation == "downDepth" {
		// 获得前一个兄弟节点
		elderBrotherList := s.treeContractDao.GetElderBrother(section.Serial, section.Depth, section.ParentId, bidsectionId, projectId, treeType)
		if len(elderBrotherList) == 0 {
			return errors.New("项目节不能降级")
		}
		elderBrother = &elderBrotherList[0]
	} else if sectionData.Operation == "upDepth" { // 3.层级升级-只要有父亲都能升级
		// 2-1 父节点深度为2不能升级
		// if (section.Depth - 1) < 2 {
		// 	return errors.New("请在项目节第三层开始编辑")
		// }
		// 获得父亲节点
		if section.ParentId == 0 {
			return errors.New("项目节不能升级")
		}
	} else {
		return errors.New("参数错误")
	}

	// 4.执行升降级
	err = s.treeContractDao.MoveDepth(section, elderBrother, sectionData.Operation, bidsectionId, projectId, treeType)
	if err != nil {
		return err
	}

	return nil
}

// 项目节的排序移动
func (s *contractService) MoveSerial(sectionData *viewmodels.TreeSectionContract, bidsectionId int, projectId int, treeType int) error {
	// 1.验证项目节ID
	treeId, err := utils.GetDecryptId(sectionData.Id)
	if err != nil {
		return err
	}
	section := s.treeContractDao.Get(treeId, bidsectionId, projectId, treeType)
	if section.Id == 0 {
		return errors.New("未找到合同项目节")
	}
	// 1-1 深度为>=2才能新增项目节
	// if section.Depth < 2 {
	// 	return errors.New("请在项目节第三层开始编辑")
	// }
	// 1-2 有合同的不能编辑(包含孩子节点)
	contractList := s.GetSectionTreeContract(section.Attribution, section.BidsectionId, section.ProjectId, treeType)
	if len(contractList) != 0 {
		return errors.New("该项目节已存在合同")
	}

	// 2.下移
	brother := &models.CmTreeContracts{}
	if sectionData.Operation == "downSerial" {
		// 获得下一个兄弟
		youngerBrotherList := s.treeContractDao.GetYoungerBrother(section.Serial, section.Depth, section.ParentId, bidsectionId, projectId, treeType)
		if len(youngerBrotherList) == 0 {
			return errors.New("项目节不能下移")
		}
		brother = &youngerBrotherList[0]
	} else if sectionData.Operation == "upSerial" {
		// 获得上一个兄弟
		elderBrotherList := s.treeContractDao.GetElderBrother(section.Serial, section.Depth, section.ParentId, bidsectionId, projectId, treeType)
		if len(elderBrotherList) == 0 {
			return errors.New("项目节不能上移")
		}
		brother = &elderBrotherList[0]
	} else {
		return errors.New("参数错误")
	}

	// 4.执行升降级
	err = s.treeContractDao.MoveSerial(section, brother, sectionData.Operation, bidsectionId, projectId, treeType)
	if err != nil {
		return err
	}
	return nil
}

// 构造项目节树
func (s *contractService) makeSectionTreeView(dataList []models.CmTreeContracts) []*viewmodels.TreeSectionContract {
	sectionList := make([]*viewmodels.TreeSectionContract, 0)
	// 生成根
	sectionRoot := &viewmodels.TreeSectionContract{}
	id, _ := comm.AesEncrypt(strconv.Itoa(0), conf.SignSecret)
	parentId, _ := comm.AesEncrypt(strconv.Itoa(-1), conf.SignSecret)
	sectionRoot.Id = id
	sectionRoot.Name = "root"
	sectionRoot.ParentId = parentId
	sectionList = append(sectionList, sectionRoot)
	for _, data := range dataList {
		section := s.makeSectionView(&data)
		sectionList = append(sectionList, section)
	}
	return sectionList
}

// 构造一个项目节View
func (s *contractService) makeSectionView(data *models.CmTreeContracts) *viewmodels.TreeSectionContract {
	section := &viewmodels.TreeSectionContract{}
	id, _ := comm.AesEncrypt(strconv.Itoa(data.TreeId), conf.SignSecret)
	parentId, _ := comm.AesEncrypt(strconv.Itoa(data.ParentId), conf.SignSecret)
	projectId, _ := comm.AesEncrypt(strconv.Itoa(data.ProjectId), conf.SignSecret)
	contractId, _ := comm.AesEncrypt(strconv.Itoa(data.ContractId), conf.SignSecret)
	bidsectionId, _ := comm.AesEncrypt(strconv.Itoa(data.BidsectionId), conf.SignSecret)
	section.Id = id
	section.Name = data.Name
	section.ParentId = parentId
	section.Depth = data.Depth + 1
	section.Serial = data.Serial
	section.Attribution = data.Attribution
	section.Code = data.Code
	section.ProjectId = projectId
	section.BidsectionId = bidsectionId
	section.ContractId = contractId

	section.ElderBrother = true
	section.IsEnd = false

	section.Name = data.Name
	section.ContractName = data.ContractName
	section.ContractCode = data.ContractCode
	section.ContractPrice = data.ContractPrice
	section.ContractReturned = data.ContractReturned
	section.ContractsPaid = data.ContractsPaid
	section.ContractStatus = data.ContractStatus
	section.ContractLocking = data.ContractLocking

	section.CreateTime = data.CreateTime.Format(conf.SysTimeform)
	return section
}
