package errors

import (
	"net/http"

	grpccodes "google.golang.org/grpc/codes"
)

type ErrorCode int32

const SUCCESS = 0

const (
	PanicError                 ErrorCode = -1
	UnrecognizedError          ErrorCode = -2
	K8SClientError             ErrorCode = -3
	AWSClientError             ErrorCode = -4
	InternalServerError        ErrorCode = -5
	ResourceNotFound           ErrorCode = -6
	ResourceConflict           ErrorCode = -7
	ResuouceIsUsed             ErrorCode = -8
	ClusterControlServiceError ErrorCode = -9
	PreconditionFailed         ErrorCode = -10

	// define common error
	IOReadFileError    ErrorCode = 1001
	B64DecodeError     ErrorCode = 1002
	ParameterInvalid   ErrorCode = 1003
	MarshalError       ErrorCode = 1004
	UnmarshalError     ErrorCode = 1005
	UnsupportedRegion  ErrorCode = 1006
	EmptyEnvError      ErrorCode = 1007
	ConvertError       ErrorCode = 1008
	ParamParseError    ErrorCode = 1009
	AbsenceOfConfig    ErrorCode = 1010
	UnsupportedBizType ErrorCode = 1011
	ConfigInvalid      ErrorCode = 1012

	// define vpc error
	VPCConflict ErrorCode = 2001

	// define privatelink error
	ConnectionNotFound        ErrorCode = 3001
	PrivateLinkAddressPending ErrorCode = 3002
	PrivateLinkAddressBlocked ErrorCode = 3003
)

type ErrorCodeExplanation struct {
	explanation string
	httpCode    int
	grpcCode    grpccodes.Code
}

func (t ErrorCode) GetHttpCode() int {
	if item, ok := explanationContainer[t]; ok {
		return item.httpCode
	}
	return http.StatusInternalServerError
}

func (t ErrorCode) GetGrpcCode() grpccodes.Code {
	if item, ok := explanationContainer[t]; ok {
		return item.grpcCode
	}
	return grpccodes.Unknown
}

func (t ErrorCode) Equal(code int32) bool {
	return code == int32(t)
}

func (t ErrorCode) Explain() string {
	if item, ok := explanationContainer[t]; ok {
		return item.explanation
	}
	return explanationContainer[UnrecognizedError].explanation
}

var explanationContainer = map[ErrorCode]ErrorCodeExplanation{
	PanicError:                 {"panic", 500, grpccodes.Internal},
	UnrecognizedError:          {"unrecognized error", 500, grpccodes.Unknown},
	K8SClientError:             {"k8s client error", 500, grpccodes.Internal},
	AWSClientError:             {"aws client error", 500, grpccodes.Internal},
	InternalServerError:        {"regionserver internal error", 500, grpccodes.Internal},
	ResourceNotFound:           {"resource not found", 404, grpccodes.NotFound},
	ResourceConflict:           {"resource conflict", 409, grpccodes.AlreadyExists},
	ResuouceIsUsed:             {"resource is used", 409, grpccodes.FailedPrecondition},
	ClusterControlServiceError: {"cluster control service error", 500, grpccodes.Internal},
	PreconditionFailed:         {"precondition failed", 412, grpccodes.FailedPrecondition},

	ParameterInvalid:   {"parameter is invalid", 400, grpccodes.InvalidArgument},
	MarshalError:       {"marshal error", 500, grpccodes.Internal},
	UnmarshalError:     {"unmarshal error", 500, grpccodes.Internal},
	UnsupportedRegion:  {"vendor or region is not supported", 400, grpccodes.FailedPrecondition},
	IOReadFileError:    {"io read file error", 500, grpccodes.Internal},
	B64DecodeError:     {"base64 decode error", 500, grpccodes.Internal},
	EmptyEnvError:      {"empty env error", 400, grpccodes.FailedPrecondition},
	ConvertError:       {"convert error", 400, grpccodes.InvalidArgument},
	ParamParseError:    {"parameter parse error", 400, grpccodes.InvalidArgument},
	AbsenceOfConfig:    {"absence of config", 500, grpccodes.Internal},
	UnsupportedBizType: {"biz_type is not supported", 400, grpccodes.FailedPrecondition},
	ConfigInvalid:      {"config is invalid", 500, grpccodes.Internal},

	ConnectionNotFound:        {"connection not found", 400, grpccodes.InvalidArgument},
	PrivateLinkAddressPending: {"private link address transition is pending", http.StatusTooEarly, grpccodes.Unavailable},
	PrivateLinkAddressBlocked: {"private link address transition is blocked", http.StatusUnprocessableEntity, grpccodes.FailedPrecondition},
}
