package auth

import (
	"net/http"

	"code.secondbit.org/uuid"
)

const getGrantTemplateName = "get_grant"

func GetGrantHandler(w http.ResponseWriter, r *http.Request, context Context) {
	if r.URL.Query().Get("client_id") == "" {
		w.WriteHeader(http.StatusBadRequest)
		context.Render(w, getGrantTemplateName, map[string]interface{}{
			"error": "Client ID must be specified in the request.",
		})
		return
	}
	clientID, err := uuid.Parse(r.URL.Query().Get("client_id"))
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		context.Render(w, getGrantTemplateName, map[string]interface{}{
			"error": "client_id is not a valid Client ID.",
		})
		return
	}
	client, err := context.GetClient(clientID)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		context.Render(w, getGrantTemplateName, map[string]interface{}{
			"internal_error": err,
		})
		return
	}
	// whether a redirect URI is valid or not depends on the number of endpoints
	// the client has registered
	numEndpoints, err := context.CountEndpoints(clientID)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		context.Render(w, getGrantTemplateName, map[string]interface{}{
			"internal_error": err,
		})
		return
	}
	redirectURI := r.URL.Query().Get("redirect_uri")
	var validURI bool
	if redirectURI != "" && numEndpoints > 1 {
		// if there's more than one registered endpoint, we need to match the
		// entire thing, character for character. So use strict checking.
		validURI, err = context.CheckEndpoint(clientID, redirectURI, true)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			context.Render(w, getGrantTemplateName, map[string]interface{}{
				"internal_error": err,
			})
			return
		}
	} else if redirectURI != "" && numEndpoints == 1 {
		// if there's exactly one endpoint, we can match only the prefix of it,
		// so don't use strict checking.
		validURI, err = context.CheckEndpoint(clientID, redirectURI, false)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			context.Render(w, getGrantTemplateName, map[string]interface{}{
				"internal_error": err,
			})
			return
		}
	} else if redirectURI == "" && numEndpoints == 1 {
		// if we don't specify the endpoint and there's only one endpoint, the
		// request is valid, and we're redirecting to that one endpoint
		validURI = true
		endpoints, err := context.ListEndpoints(clientID, 1, 0)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			context.Render(w, getGrantTemplateName, map[string]interface{}{
				"internal_error": err,
			})
			return
		}
		if len(endpoints) != 1 {
			validURI = false
		} else {
			redirectURI = endpoints[0].URI.String()
		}
	} else {
		validURI = false
	}
	if !validURI {
		w.WriteHeader(http.StatusBadRequest)
		context.Render(w, getGrantTemplateName, map[string]interface{}{
			"error": "The redirect_uri specified is not valid.",
		})
		return
	}
	if r.URL.Query().Get("response_type") != "code" {
		// TODO: redirect error
	}
	//scope := r.URL.Query().Get("scope")
	//state := r.URL.Query().Get("state")
	if r.Method == "POST" {
		// TODO: CSRF protection
		if r.PostFormValue("grant") == "approved" {
			// TODO: redirect
		} else {
			// TODO: redirect error
		}
	}
	w.WriteHeader(http.StatusOK)
	context.Render(w, getGrantTemplateName, map[string]interface{}{
		"client": client,
	})
}
