/*
 * Copyright 2017-2019 Kopano and its licensors
 *
 * 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,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package oidc

import (
	"fmt"
	"net/http"

	"github.com/libregraph/lico/utils"
)

// OAuth2Error defines a general OAuth2 error with id and decription.
type OAuth2Error struct {
	ErrorID          string `json:"error"`
	ErrorDescription string `json:"error_description"`
}

// Error implements the error interface.
func (err *OAuth2Error) Error() string {
	return err.ErrorID
}

// Description implements the ErrorWithDescription interface.
func (err *OAuth2Error) Description() string {
	return err.ErrorDescription
}

// NewOAuth2Error creates a new error with id and description.
func NewOAuth2Error(id string, description string) utils.ErrorWithDescription {
	return &OAuth2Error{id, description}
}

// WriteWWWAuthenticateError writes the provided error with the provided
// http status code to the provided http response writer as a
// WWW-Authenticate header with comma separated fields for id and
// description.
func WriteWWWAuthenticateError(rw http.ResponseWriter, code int, err error) {
	if code == 0 {
		code = http.StatusUnauthorized
	}

	var description string
	switch err.(type) {
	case utils.ErrorWithDescription:
		description = err.(utils.ErrorWithDescription).Description()
	default:
	}

	rw.Header().Set("WWW-Authenticate", fmt.Sprintf("error=\"%s\", error_description=\"%s\"", err.Error(), description))
	rw.WriteHeader(code)
}

// IsErrorWithID returns true if the given error is an OAuth2Error error with
// the given ID.
func IsErrorWithID(err error, id string) bool {
	if err == nil {
		return false
	}

	oauth2Error, ok := err.(*OAuth2Error)
	if !ok {
		return false
	}

	return oauth2Error.ErrorID == id
}
