package web

import (
	"fmt"
	"io"
	"net/http"
	"strings"

	"code.osinet.fr/fgm/kurz/domain"
	"github.com/gorilla/mux"
)

/*
Template variables:

  - assetsBaseURL http://plusvite-cdn.osinet.eu
  - FullyQualifiedShortURL      (short string)
  - SiteBaseURL       http://plusvite.net/
  - FullyQualifiedTargetURL     (target string)
  - RefreshDelay                (seconds int)
  - SiteName                    PlusVite
*/

type bytes = []byte

func build403(w http.ResponseWriter, short string) {
	data := struct {
		FullyQualifiedShortURL string
		Globals
	}{
		short,
		globals,
	}

	sw := &strings.Builder{}
	err := tmpl.ExecuteTemplate(sw, "403", data)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
	} else {
		w.WriteHeader(http.StatusForbidden)
		io.Copy(w, strings.NewReader(sw.String()))
	}
}

func build404(w http.ResponseWriter, short string) {
	data := struct {
		FullyQualifiedShortURL string
		Globals
	}{
		short,
		globals,
	}

	sw := &strings.Builder{}
	err := tmpl.ExecuteTemplate(sw, "404", data)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
	} else {
		w.WriteHeader(http.StatusNotFound)
		io.Copy(w, strings.NewReader(sw.String()))
	}
}

func build451(w http.ResponseWriter, router *mux.Router, short string) {
	hr := router.Get(RouteGetRoot)
	_, err := hr.URL()
	if err != nil {
		fmt.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	data := struct {
		FullyQualifiedShortURL string
		Globals
	}{
		short,
		globals,
	}

	sw := &strings.Builder{}
	err = tmpl.ExecuteTemplate(sw, "404", data)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
	} else {
		w.WriteHeader(http.StatusNotFound)
		io.Copy(w, strings.NewReader(sw.String()))
	}
}

// handleGetShort handles path /<short>
func handleGetShort(w http.ResponseWriter, r *http.Request, router *mux.Router) {
	short, ok := mux.Vars(r)["short"]
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	target, err := domain.GetTargetURL(short)
	// Happy path.
	if err == nil {
		w.Header().Set("Location", target)
		w.WriteHeader(http.StatusTemporaryRedirect)
		return
	}

	// Very sad path.
	domainErr, ok := err.(domain.Error)
	if !ok {
		// All errors return by the API should be domain-specific errors.
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	// Normal sad paths.
	switch domainErr.Kind {
	case domain.ShortNotFound:
		build404(w, short)

	case domain.TargetBlockedError:
		build403(w, short)

	case domain.TargetCensoredError:
		build451(w, router, short)

	default:
		// TargetInvalid is not supposed to happen in this case, so it is an internal error too.
		w.WriteHeader(http.StatusInternalServerError)
	}
}