package main

import (
	"encoding/json"
	"fmt"
	"math/big"
	"reflect"
	"time"
)


func NewSchema(arg string) (*Schema, error) {
	schema := &Schema{
		LeadgerFields: make(map[string]SchemaLeadgerParameters),
		StorageFields: make(map[string]SchemaParameters),
	}
	var argMap map[string]interface{}
	if err := json.Unmarshal([]byte(arg), &argMap); err != nil {
		return nil, err
	}
	if (argMap["storage_fields"] != nil || argMap["leadger_fields"] != nil) && argMap["schema_auth"] != nil && argMap["auth"] != nil {
		if err := json.Unmarshal([]byte(arg), schema); err != nil {
			return nil, err
		}
		//检查schema leadger字段
		err := leadgerFieldsCheck(&schema.LeadgerFields)
		if err != nil {
			return nil, err
		}
		return schema, nil
	}
	for k, v := range argMap { //假设用户只传递了map类型的信息，我们则默认它全部都是存储字段
		schema.StorageFields[k] = SchemaParameters{
			Value: v,
			PAuth: Auth{},
		}
	}
	return schema, nil
}


func leadgerFieldsCheck(leadgerFields *map[string]SchemaLeadgerParameters) error {
	for k, fields := range *leadgerFields {
		if fields.FCheck == nil {
			fields.FCheck = &Checks{
				FType:    "big.int",
				Must:     false,
				Fieldlen: 1,
			}
		} else {
			if fields.FCheck.FType != "big.int" {
				return fmt.Errorf("%s fields type must is big.int", k)
			} else if !(fields.FCheck.Fieldlen > 0) {
				return fmt.Errorf("%s fields length must is greater than zero", k)
			}
		}
		if len(fields.PAuth.Extract.Roles) == 0 && len(fields.PAuth.Extract.Users) == 0 {

		}
	}
	return nil
}
/*
	schema 权限检查,权限组是否满足权限
*/
func (schema *Schema) AuthorityCheck(authority AuthGroup, name, owner string) error {
	var auths map[string]int64
	if IsUsers {
		auths = authority.Users
	} else {
		auths = authority.Roles
	}
	if len(auths) == 0 {
		return nil
	}
	for k, v := range auths {
		if k == name || (k == "owner" && name == owner) {
			if v == 0 || v > time.Now().Unix() {
				return nil
			} else {
				return fmt.Errorf("%s user permission period ", name)
			}
		}
	}
	return fmt.Errorf("%s user does not have permission", name)

}

/*
	schema 写权限检查,权限组是否满足权限
*/
func (schema *Schema) WriteCheck(name, owner string) error {
	return schema.AuthorityCheck(schema.SchemaAuth.Write,name,owner)
}


/*
	schema 对应数据总写权限检查,权限组是否满足权限
*/
func (schema *Schema) AllWriteCheck(name, owner string) error {
	return schema.AuthorityCheck(schema.SAuth.Write,name,owner)
}

/*
	数据的写权限检查
*/
func (schema *Schema) DataWriteCheck(checks map[string]interface{}, commonName, owner string) error{
	//if err := schema.WriteCheck(commonName,owner) ; err != nil{
	//	return  nil
	//}
	for k, _ := range checks {
		if schemaV, ok :=  schema.StorageFields[k]; !ok {
			return  fmt.Errorf("inexistence %s field! ",k)
		} else {
			if err := schema.AuthorityCheck(schemaV.PAuth.Write, commonName, owner); err != nil {
				return  fmt.Errorf("%s field authority check fail, %s ",k,err)
			}
		}
	}
	return  nil
}

/*
	schema 读权限检查,权限组是否满足权限
*/
func (schema *Schema) ReadCheck(name, owner string) error {
	return schema.AuthorityCheck(schema.SchemaAuth.Read,name,owner)
}

/*
	schema 对应数据总读权限检查,权限组是否满足权限
*/
func (schema *Schema) AllReadCheck(name, owner string) error {
	return schema.AuthorityCheck(schema.SAuth.Read,name,owner)
}
/*
	schema 读过滤
*/
func (schema *Schema) ReadFiler(checks map[string]interface{}, commonName, owner string) (map[string]interface{}, error) {
	//if err := schema.ReadCheck(commonName,owner) ; err != nil{
	//	return checks, nil
	//}
	for k, schemaV := range schema.StorageFields {
		if err := schema.AuthorityCheck(schemaV.PAuth.Read, commonName, owner); err != nil {
			checks[k] = defValue
		}
	}

	for k, schemaV := range schema.LeadgerFields {
		if err := schema.AuthorityCheck(schemaV.PAuth.Read, commonName, owner); err != nil {
			checks[k] = defValue
		}
	}

	return checks, nil
}


func (schema *Schema) DataReadCheck(checks map[string]interface{}, commonName, owner string) error{
	//if err := schema.WriteCheck(commonName,owner) ; err != nil{
	//	return  nil
	//}
	for k, _ := range checks {
		if schemaV, ok :=  schema.StorageFields[k]; !ok {
			return  fmt.Errorf("inexistence %s field! ",k)
		} else {
			if err := schema.AuthorityCheck(schemaV.PAuth.Read, commonName, owner); err != nil {
				return  fmt.Errorf("%s field authority check fail, %s ",k,err)
			}
		}
	}
	return  nil
}


/*
	进行Schema 字段的格式匹配
*/
func (schema *Schema)SchemaMatched(checks map[string]interface{})error{
	if len(schema.StorageFields)+len(schema.LeadgerFields) != len(checks) {
		return fmt.Errorf("field length is less than the schema field length ! ")
	}
	for k, v := range schema.StorageFields {
		if schemaV, ok := checks[k]; !ok {
			return fmt.Errorf("There is no input storage field %s ", k)
		} else {
			if parameterS, ok := v.Value.(map[string]interface{}); ok {
				if parameterC, ok := schemaV.(map[string]interface{}); !ok {
					return fmt.Errorf("The input field %s does not match the output field format ", k)
				} else {
					err := backUpCheck(parameterS, parameterC)
					if err != nil {
						return err
					}
				}
			}
		}
	}
	for k, _ := range schema.LeadgerFields {
		if _, ok := checks[k]; !ok {
			return fmt.Errorf("There is no input leadger field %s ", k)
		}
	}
	return nil
}

func backUpCheck(backUp map[string]interface{}, checkmap map[string]interface{}) error {
	if len(backUp) != len(checkmap) {
		return fmt.Errorf("The input backup field length is less than the schema backup field length ! ")
	}
	for k, _ := range checkmap {
		if _, ok := backUp[k]; !ok {
			return fmt.Errorf("There is no input backup field %s ", k)
		}
	}
	return nil
}

func (schema *Schema)FieldsCheck(checks map[string]interface{})error{
	for k, schemaV := range schema.StorageFields {
		if _, ok := checks[k]; !ok {
			return fmt.Errorf("There is no input storage field %s ", k)
		}
		if schemaV.FCheck != nil && schemaV.FCheck.FType != ""  {
			if err := schema.fieldCheckout(schemaV.FCheck, checks[k]); err != nil {
				return fmt.Errorf("%s field check err:%s ", k, err)
			}
		}
	}
	for k, schemaV := range schema.LeadgerFields {
		if _, ok := checks[k]; !ok {
			return fmt.Errorf("There is no input storage field %s ", k)
		}
		if schemaV.FCheck != nil && schemaV.FCheck.FType != "" {
			if err := schema.fieldCheckout(schemaV.FCheck, checks[k]); err != nil {
				return fmt.Errorf("%s field check err:%s ", k, err)
			}
		}
	}
	return nil
}

func (schema *Schema)FieldsFormatCheck(checks map[string]interface{})error{
	for k, _ := range checks{
		fcheck := &Checks{}
		sfield,ok := schema.StorageFields[k]
		if ok{
			fcheck = sfield.FCheck
		}else{
			lfield,ok := schema.LeadgerFields[k]
			if !ok{
				return fmt.Errorf("%s field check inexistence in schema", k, )
			}
			fcheck = lfield.FCheck
		}
		if fcheck != nil && fcheck.FType != "" && checks[k] != nil {
			if err := schema.fieldCheckout(fcheck, checks[k]); err != nil {
				return fmt.Errorf("%s field check err:%s ", k, err)
			}
		}
	}
	return nil
}

func (schema *Schema)fieldCheckout(check *Checks, val interface{}) error {
	fType := reflect.TypeOf(val).String()

	switch check.FType {
	case "string":
		if fType != "string" {
			return fmt.Errorf("fields type does not match the defined string type! ")
		}
		if check.Must && (val == "") {
			return fmt.Errorf("fields can not be empty")
		}
		value := val.(string)
		if len([]rune(value)) > check.Fieldlen {
			return fmt.Errorf("fields length cannot be greater than %d ", check.Fieldlen)
		}
	case "int", "int16", "int32", "int64", "float32", "float64":
		if fType != "float64" {
			return fmt.Errorf("fields type does not match the defined %s type! ", check.FType)
		}
		value := val.(float64)
		if check.Must && (value == 0) {
			return fmt.Errorf("fields can not be 0")
		}
		if check.Fieldlen != 0 && value < 0 {
			return fmt.Errorf("fields cannot be negative")
		}
	case "time.Time":
		if fType != "string" {
			return fmt.Errorf("fields type does not match the defined time.Time type! ")
		}
		dateStr := reflect.ValueOf(val).String()
		if check.Must && dateStr == "" {
			return fmt.Errorf("fields cannot be empty")
		}
		if _, err := time.Parse("2006-01-02 15:04:05", dateStr); err != nil {
			return fmt.Errorf(err.Error())
		}

		//if check.Must && (dateStr == "0001-01-01 00:00:00 +0000 UTC"|| dateStr == "0001-01-01T00:00:00Z"){
		//	return fmt.Errorf("fields cannot be initial value")
		//}
	case "big.int":
		if fType != "string" {
			return fmt.Errorf("fields type does not match the defined big.int type! ")
		}
		number := new(big.Int)
		dateStr := reflect.ValueOf(val).String()
		_, ok := number.SetString(dateStr, 10)
		if !ok {
			return fmt.Errorf("parameter resolution failed ")
		}
	case "object","struct":
		if fType != "map[string]interface {}" {
			return fmt.Errorf("fields type does not match the defined big.int type! ")
		}

	default:
		fmt.Errorf("fields type no match! ")
	}
	return nil
}

