package services

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"reflect"
	"strconv"

	"go.mod/web/utils"

	"github.com/kataras/iris/v12"
	"go.mod/dao"
	"go.mod/datasource"
	"go.mod/web/viewmodels"
)

type RuleService interface {
	Get(pid int, id int) viewmodels.ViewRule
	Post(pid int, id int, key string, value string) error
	AutoCode(bid int, pid int, codeType string) (string, error)
	ValidRule(ctx iris.Context) (viewmodels.ValidField, error)
}

// //返回service操作类
type ruleService struct {
	daoRule       *dao.RuleDao
	daoSafe       *dao.SafeDao
	daoContract   *dao.ContractDao
	validAutoPath string
}

//创建项目用户service
func NewRuleService() RuleService {
	return &ruleService{
		validAutoPath: "/api/rule/auto",
		daoRule:       dao.NewRuleDao(datasource.InstanceDbMaster()),
		daoSafe:       dao.NewSafeDao(datasource.InstanceDbMaster()),
		daoContract:   dao.NewContractDao(datasource.InstanceDbMaster()),
	}
}

func (s *ruleService) Get(pid int, id int) viewmodels.ViewRule {
	data := s.daoRule.FindByPidWithBid(pid, id)
	viewData := viewmodels.ViewRule{SafeRule: data.SafeRule, QualityRule: data.QualityRule, ContractRule: data.ContractRule}
	return viewData
}

func (s *ruleService) Post(pid int, id int, key string, value string) error {
	err := s.daoRule.UpdateOrCreate(pid, id, key, value)
	return err
}

// type Code struct {
// 	Date string `from:"date" json:"date"`
// 	Text string `from:"text" json:"text"`
// 	Name string `from:"name" json:"name"`
// 	Code string `from:"code" json:"code"`
// }

// 生成code
func (s *ruleService) AutoCode(bid int, pid int, codeType string) (string, error) {
	// 获取该标段的规则
	rule := s.daoRule.FindByPidWithBid(pid, bid)
	if codeType == "safeRule" {
		if rule.SafeRule == "" {
			return "", errors.New("该标段未设置编号规则!")
		}
		var code viewmodels.RuleCode
		err := json.Unmarshal([]byte(rule.SafeRule), &code)
		if err == nil {
			total, err := s.daoSafe.CountRuleCode(bid)
			value := reflect.ValueOf(code)
			for i := 0; i < value.NumField(); i++ {
				b := fmt.Sprint(value.Field(i))
				if b == code.Code {
					k, _ := strconv.Atoi(b)
					code.Code = utils.CreateRuleCode(int64(k), total, len(code.Code))
				}
			}

			e, err := json.Marshal(code)
			if err != nil {
				return "", err
			}
			return string(e), err
		}
	} else if codeType == "contractRule" {
		if rule.ContractRule == "" {
			return "", errors.New("该标段未设置编号规则!")
		}
		var code viewmodels.RuleCode
		err := json.Unmarshal([]byte(rule.ContractRule), &code)
		if err == nil {
			total, err := s.daoContract.CountRuleCode(bid)
			if err != nil {
				return "", err
			}
			value := reflect.ValueOf(code)
			for i := 0; i < value.NumField(); i++ {
				b := fmt.Sprint(value.Field(i))
				if b == code.Code {
					k, _ := strconv.Atoi(b)
					code.Code = utils.CreateRuleCode(int64(k), total, len(code.Code))
				}
			}

			e, err := json.Marshal(code)
			if err != nil {
				return "", err
			}
			return string(e), err
		}
	} else {
		if rule.QualityRule == "" {
			return "", errors.New("该标段未设置编号规则!")
		}
		var code viewmodels.RuleCode
		err := json.Unmarshal([]byte(rule.QualityRule), &code)
		if err == nil {
			total, err := s.daoSafe.CountRuleCode(bid)
			value := reflect.ValueOf(code)
			for i := 0; i < value.NumField(); i++ {
				b := fmt.Sprint(value.Field(i))
				if b == code.Code {
					k, _ := strconv.Atoi(b)
					code.Code = utils.CreateRuleCode(int64(k), total, len(code.Code))
				}
			}

			e, err := json.Marshal(code)
			if err != nil {
				return "", err
			}
			return string(e), err
		}
	}
	return "", errors.New("生成code失败")
}

func (s *ruleService) ValidRule(ctx iris.Context) (viewmodels.ValidField, error) {
	safeVaild := viewmodels.ValidField{}
	if ctx.Method() == "GET" {
		err := ctx.ReadForm(&safeVaild)
		if err != nil {
			log.Println("safe-ValidRule-ReadForm转换异常, error=", err)
			return safeVaild, err
		}
		err = safeVaild.Validate()
		return safeVaild, err
	}

	if ctx.Method() == "POST" {
		err := ctx.ReadJSON(&safeVaild)
		if err != nil {
			log.Println("safe-ValidRule-ReadJson转换异常, error=", err)
			return safeVaild, err
		}
		if ctx.Path() == s.validAutoPath {
			err = safeVaild.ValidateAuto()
		} else {
			err = safeVaild.Validate()
		}

	}
	return safeVaild, nil

}
