package webfinger

import (
	"encoding/json"
	"errors"
	"net/http"
)

// WebFingerPath defines the default path of the webfinger handler.
const WebFingerPath = "/.well-known/webfinger"

func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	//TODO: support host-meta as a path

	path := r.URL.Path
	switch path {
	case WebFingerPath:
		s.Webfinger(w, r)
	default:
		s.NotFoundHandler.ServeHTTP(w, r)
	}
}

// Webfinger is the webfinger handler
func (s *Service) Webfinger(w http.ResponseWriter, r *http.Request) {
	s.runPrehandlers(w, r)

	if r.TLS == nil && s.NoTLSHandler != nil {
		s.NoTLSHandler.ServeHTTP(w, r)
		return
	}

	//NOTE: should this run before or after the pre-run handlers?
	if r.Method != "GET" {
		s.MethodNotSupportedHandler.ServeHTTP(w, r)
		return
	}

	if len(r.URL.Query()["resource"]) != 1 {
		s.MalformedRequestHandler.ServeHTTP(w, addError(r, errors.New("Malformed resource parameter")))
		return
	}
	resource := r.URL.Query().Get("resource")
	var a account
	if err := a.ParseString(resource); err != nil {
		s.MalformedRequestHandler.ServeHTTP(w, addError(r, err))
		return
	}

	relStrings := r.URL.Query()["rel"]
	var rels []Rel
	for _, r := range relStrings {
		rels = append(rels, Rel(r))
	}

	rsc, err := s.Resolver.FindUser(a.Name, a.Hostname, r.Host, rels)
	if err != nil {
		if !s.Resolver.IsNotFoundError(err) {
			s.ErrorHandler.ServeHTTP(w, addError(r, err))
			return
		}

		rsc, err = s.Resolver.DummyUser(a.Name, a.Hostname, rels)
		if err != nil && !s.Resolver.IsNotFoundError(err) {
			s.ErrorHandler.ServeHTTP(w, addError(r, err))
			return
		} else if s.Resolver.IsNotFoundError(err) {
			s.NotFoundHandler.ServeHTTP(w, r)
			return
		}
	}

	if err := json.NewEncoder(w).Encode(&rsc); err != nil {
		s.ErrorHandler.ServeHTTP(w, addError(r, err))
		return
	}
}

func (s *Service) runPrehandlers(w http.ResponseWriter, r *http.Request) {
	if s.PreHandlers == nil {
		return
	}

	for _, val := range s.PreHandlers {
		if val != nil {
			val.ServeHTTP(w, r)
		}
	}
}

func (s *Service) defaultErrorHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusInternalServerError)
}

func (s *Service) defaultNotFoundHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNotFound)
}

func (s *Service) defaultMethodNotSupportedHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusMethodNotAllowed)
}

func (s *Service) defaultMalformedRequestHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusBadRequest)
}

func (s *Service) defaultNoTLSHandler(w http.ResponseWriter, r *http.Request) {
	u := *r.URL
	u.Scheme = "https"
	w.Header().Set("Location", u.String())
	w.WriteHeader(http.StatusSeeOther)
}
