package main

import (
	"notabug.org/apiote/amuse/libamuse"
	"notabug.org/apiote/amuse/front"
	"notabug.org/apiote/amuse/tmdb"

	"errors"
	"fmt"
	"net/http"
	"strconv"
	"strings"
)

func person(w http.ResponseWriter, r *http.Request) {
	acceptLanguages := r.Header.Get("Accept-Language")
	etag := r.Header.Get("Etag")
	mimetype := strings.Split(r.Header.Get("Accept"), ",")[0]

	defer recovery(acceptLanguages, mimetype, w)

	path := strings.Split(r.URL.Path[1:], "/")
	_, err := strconv.ParseInt(path[1], 10, 64)
	if err != nil {
		renderError(400, w, err, acceptLanguages, mimetype)
		return
	} else if len(path) > 2 {
		renderError(404, w, nil, acceptLanguages, mimetype)
		return
	}
	serie, err := libamuse.ShowPerson(path[1], etag, acceptLanguages, mimetype)
	render(serie, err, w, acceptLanguages, mimetype)
}

func serie(w http.ResponseWriter, r *http.Request) {
	acceptLanguages := r.Header.Get("Accept-Language")
	etag := r.Header.Get("Etag")
	mimetype := strings.Split(r.Header.Get("Accept"), ",")[0]

	defer recovery(acceptLanguages, mimetype, w)

	path := strings.Split(r.URL.Path[1:], "/")
	_, err := strconv.ParseInt(path[1], 10, 64)
	if err != nil {
		renderError(400, w, err, acceptLanguages, mimetype)
		return
	} else if len(path) > 2 {
		renderError(404, w, nil, acceptLanguages, mimetype)
		return
	}
	serie, err := libamuse.ShowSerie(path[1], etag, acceptLanguages, mimetype)
	render(serie, err, w, acceptLanguages, mimetype)
}

func film(w http.ResponseWriter, r *http.Request) {
	acceptLanguages := r.Header.Get("Accept-Language")
	etag := r.Header.Get("Etag")
	mimetype := strings.Split(r.Header.Get("Accept"), ",")[0]

	defer recovery(acceptLanguages, mimetype, w)

	path := strings.Split(r.URL.Path[1:], "/")
	_, err := strconv.ParseInt(path[1], 10, 64)
	if err != nil {
		renderError(400, w, err, acceptLanguages, mimetype)
		return
	} else if len(path) > 2 {
		renderError(404, w, nil, acceptLanguages, mimetype)
		return
	}
	film, err := libamuse.ShowFilm(path[1], etag, acceptLanguages, mimetype)
	render(film, err, w, acceptLanguages, mimetype)
}

func search(w http.ResponseWriter, r *http.Request) {
	acceptLanguages := r.Header.Get("Accept-Language")
	mimetype := strings.Split(r.Header.Get("Accept"), ",")[0]

	defer recovery(acceptLanguages, mimetype, w)

	path := strings.Split(r.URL.Path[1:], "/")
	if len(path) > 2 {
		renderError(404, w, nil, acceptLanguages, mimetype)
		return
	}
	query := r.URL.Query().Get("q")
	page := r.URL.Query().Get("page")
	results, err := libamuse.PerformSearch(query, acceptLanguages, mimetype, page)
	render(results, err, w, acceptLanguages, mimetype)
}

func index(w http.ResponseWriter, r *http.Request) {
	acceptLanguages := r.Header.Get("Accept-Language")
	mimetype := strings.Split(r.Header.Get("Accept"), ",")[0]

	defer recovery(acceptLanguages, mimetype, w)

	path := strings.Split(r.URL.Path[1:], "/")
	if path[0] != "" {
		renderError(404, w, nil, acceptLanguages, mimetype)
		return
	}
	index, err := libamuse.ShowIndex(acceptLanguages, mimetype)
	render(index, err, w, acceptLanguages, mimetype)
}

func about(w http.ResponseWriter, r *http.Request) {
	acceptLanguages := r.Header.Get("Accept-Language")
	mimetype := strings.Split(r.Header.Get("Accept"), ",")[0]

	defer recovery(acceptLanguages, mimetype, w)

	about, err := libamuse.ShowAbout(acceptLanguages, mimetype)
	render(about, err, w, acceptLanguages, mimetype)
}

func main() {
	fs := http.FileServer(http.Dir("static"))
	http.HandleFunc("/", index)
	http.Handle("/static/", http.StripPrefix("/static/", fs))
	http.HandleFunc("/about", about)
	http.HandleFunc("/items/", search)
	http.HandleFunc("/films/", film)
	http.HandleFunc("/series/", serie)
	http.HandleFunc("/persons/", person)
	http.ListenAndServe(":5008", nil)
}

func recovery(languages, mimetype string, w http.ResponseWriter) {
	if r := recover(); r != nil {
		renderError(500, w, errors.New(r.(string)), languages, mimetype)
	}
}

func render(result string, e error, w http.ResponseWriter, languages, mimetype string) {
	if e != nil {
		if _, ok := e.(front.NoSuchRendererError); ok {
			renderError(406, w, e, languages, mimetype)
		} else if httpError, ok := e.(tmdb.HttpError); ok {
			renderError(httpError.Status, w, httpError, languages, mimetype)
		} else {
			renderError(500, w, e, languages, mimetype)
		}
	} else {
		fmt.Fprint(w, result)
	}
}

func renderError(code int, w http.ResponseWriter, e error, languages, mimetype string) {
	w.WriteHeader(code)
	if code != 406 {
		errorPage, err := libamuse.ShowErrorPage(code, languages, mimetype)
		if err != nil {
			fmt.Fprintf(w, "Fatal error while rendering error %d.\nContact admin.", code)
		}
		fmt.Fprint(w, errorPage)
	}
}
