/*
 * Copyright 2021 PingCAP, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package errors

import (
	"fmt"
	"net/http"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type ErrorInfo struct {
	Code    uint32 `json:"code"`
	Message string `json:"message"`
}

func NewErrorInfo(major, minor int, message string) ErrorInfo {
	return ErrorInfo{Code: uint32(major)*10000 + uint32(minor), Message: message}
}

func (err ErrorInfo) getMajorCode() int {
	return int(err.Code / 10000)
}

func (err ErrorInfo) getMinorCode() int {
	return int(err.Code % 10000)
}

func (err ErrorInfo) Error() string {
	return fmt.Sprintf("code: %d, message: %s", err.Code, err.Message)
}

func (err ErrorInfo) StatusCode() int {
	return err.getMinorCode()
}

// error code [1000000, 2000000) belong to business layer error.
// error code [2000000, 3000000) belong to k8s api error.
// error code [3000000, 4000000) belong to flink client error.

var (
	ErrInvalidParameter = func(msg string) ErrorInfo { return NewErrorInfo(100, http.StatusBadRequest, msg) }
	ErrInternal         = func(msg string) ErrorInfo {
		return NewErrorInfo(100, http.StatusInternalServerError, msg)
	}
	ErrUnimplemented = func() ErrorInfo {
		return NewErrorInfo(100, http.StatusNotImplemented, "unimplemented")
	}
	ErrUnauthorized    = func(msg string) ErrorInfo { return NewErrorInfo(100, http.StatusUnauthorized, msg) }
	ErrTokenExpired    = func() ErrorInfo { return NewErrorInfo(101, http.StatusUnauthorized, "token invalid") }
	ErrForbidden       = func(msg string) ErrorInfo { return NewErrorInfo(100, http.StatusForbidden, msg) }
	ErrMaliciousConfig = func(msg string) ErrorInfo { return NewErrorInfo(102, http.StatusInternalServerError, msg) }
	ErrAlreadyExisted  = func(msg string) ErrorInfo { return NewErrorInfo(103, http.StatusBadRequest, msg) }
	ErrNotFound        = func(msg string) ErrorInfo { return NewErrorInfo(100, http.StatusNotFound, msg) }
	// TODO: we need a help function to convert error form k8s to our business error.

	ErrFromK8sStatus = func(status metav1.Status) ErrorInfo { return NewErrorInfo(200, int(status.Code), status.Message) }

	ErrFromFlinkClient = func(msg string) ErrorInfo { return NewErrorInfo(300, http.StatusInternalServerError, msg) }
)
