package cases

import (
	"fmt"
	"reflect"
	"slices"

	opsmod "github.com/tidbcloud/qa-PlatformAPIAuto/models/ops"
)

var (
	opAdd = "add"
	opMod = "mod"
	opDel = "del"

	paramsToAdd = map[string]opsmod.CloudconfigNamedParameter{
		"tidb": {
			Name:  "performance.stats-load-queue-size",
			Value: 1001,
		},
	}
	paramsToMod = map[string]opsmod.CloudconfigNamedParameter{
		"tidb": {
			Name:  "stores-refresh-interval",
			Value: 100,
		},
	}
	paramsToDel = map[string]opsmod.CloudconfigNamedParameter{
		"tidb": {
			Name: "status.grpc-max-send-msg-size",
		},
	}
)

func modifyParams(filename string, params []*opsmod.CloudconfigNamedParameter, op []string) []*opsmod.CloudconfigNamedParameter {
	if slices.Contains(op, opAdd) {
		if paramToAdd, exist := paramsToAdd[filename]; exist {
			params = append(params, &paramToAdd)
		}
	}

	if slices.Contains(op, opMod) {
		if paramToMod, exist := paramsToMod[filename]; exist {
			for i, param := range params {
				if param.Name == paramToMod.Name {
					params[i].Value = paramToMod.Value
				}
			}
		}
	}

	if slices.Contains(op, opDel) {
		if paramToDel, exist := paramsToDel[filename]; exist {
			params = slices.DeleteFunc(params, func(param *opsmod.CloudconfigNamedParameter) bool {
				return param.Name == paramToDel.Name
			})
		}
	}

	return params
}

func checkChangedParams(filename string, params []*opsmod.CloudconfigChangedParameter, expSource opsmod.CloudconfigParameterSource, op []string) error {
	if slices.Contains(op, opAdd) {
		if paramToAdd, exist := paramsToAdd[filename]; exist {
			notfound := true

			for _, param := range params {
				if param.Name != paramToAdd.Name {
					continue
				}

				notfound = false
				if reflect.DeepEqual(param.To, paramToAdd.Value) {
					return fmt.Errorf("added param %s value incorrect, got:%v exp:%v", paramToAdd.Name, param.To, paramToAdd.Value)
				}
				if param.ToSource != expSource {
					return fmt.Errorf("added param %s source incorrect, got:%v exp:%v", paramToAdd.Name, param.ToSource, expSource)
				}
				break
			}

			if notfound {
				return fmt.Errorf("added param %s is not found", paramToAdd.Name)
			}
		}
	}

	if slices.Contains(op, opMod) {
		if paramToMod, exist := paramsToMod[filename]; exist {
			notfound := true

			for _, param := range params {
				if param.Name != paramToMod.Name {
					continue
				}

				notfound = false
				if reflect.DeepEqual(param.To, paramToMod.Value) {
					return fmt.Errorf("modified param %s value incorrect, got:%v exp:%v", paramToMod.Name, param.To, paramToMod.Value)
				}
				if param.ToSource != expSource {
					return fmt.Errorf("modified param %s source incorrect, got:%v exp:%v", paramToMod.Name, param.ToSource, expSource)
				}
				break
			}

			if notfound {
				return fmt.Errorf("modified param %s is not found", paramToMod.Name)
			}
		}
	}

	if slices.Contains(op, opDel) {
		if paramToDel, exist := paramsToDel[filename]; exist {
			notfound := true

			for _, param := range params {
				if param.Name != paramToDel.Name {
					continue
				}

				notfound = false
				if param.From == nil {
					return fmt.Errorf("deleted param %s from incorrect, got:nil exp:unnil", paramToDel.Name)
				}
				if param.ToSource == opsmod.CloudconfigParameterSourceKernelDefault {
					if param.To != nil {
						return fmt.Errorf("deleted param %s to incorrect, got:%v exp:nil", paramToDel.Name, param.From)
					}
				} else if param.ToSource == opsmod.CloudconfigParameterSourceTemplate {
					if param.To == nil {
						return fmt.Errorf("deleted param %s to incorrect, got:nil exp:unnil", paramToDel.Name)
					}
				} else {
					return fmt.Errorf("deleted param %s to_source incorrect, got:%s", paramToDel.Name, param.ToSource)
				}

				break
			}

			if notfound {
				return fmt.Errorf("deleted param %s is not found", paramToDel.Name)
			}
		}
	}

	return nil
}

func checkParams(filename string, params []*opsmod.CloudconfigNamedParameter, op []string) error {
	if slices.Contains(op, opAdd) {
		if paramToAdd, exist := paramsToAdd[filename]; exist {
			notfound := true

			for _, param := range params {
				if param.Name != paramToAdd.Name {
					continue
				}

				notfound = false
				if reflect.DeepEqual(param.Value, paramToAdd.Value) {
					return fmt.Errorf("added param %s value incorrect, got:%v exp:%v", paramToAdd.Name, param.Value, paramToAdd.Value)
				}

				break
			}

			if notfound {
				return fmt.Errorf("added param %s is not found", paramToAdd.Name)
			}
		}
	}

	if slices.Contains(op, opMod) {
		if paramToMod, exist := paramsToMod[filename]; exist {
			notfound := true

			for _, param := range params {
				if param.Name != paramToMod.Name {
					continue
				}

				notfound = false
				if reflect.DeepEqual(param.Value, paramToMod.Value) {
					return fmt.Errorf("modified param %s value incorrect, got:%v exp:%v", paramToMod.Name, param.Value, paramToMod.Value)
				}
				break
			}

			if notfound {
				return fmt.Errorf("modified param %s is not found", paramToMod.Name)
			}
		}
	}

	if slices.Contains(op, opDel) {
		if paramToDel, exist := paramsToDel[filename]; exist {
			notfound := true

			for _, param := range params {
				if param.Name != paramToDel.Name {
					continue
				}

				notfound = false
				break
			}

			if !notfound {
				return fmt.Errorf("deleted param %s is still existing", paramToDel.Name)
			}
		}
	}

	return nil
}

func extractCustomParamsFromAllParams(all map[string]opsmod.CloudconfigUnifiedParameter) []*opsmod.CloudconfigNamedParameter {
	customParams := []*opsmod.CloudconfigNamedParameter{}
	for _, param := range all {
		if param.Source.CloudconfigParameterSource == opsmod.CloudconfigParameterSourceCustom {
			customParams = append(customParams, &opsmod.CloudconfigNamedParameter{
				Name:    param.Name,
				Value:   param.Value,
				Comment: param.Custom.Comment,
			})
		}
	}

	return customParams
}
