package front

import (
	"notabug.org/apiote/amuse/accounts"
	"notabug.org/apiote/amuse/config"
	"notabug.org/apiote/amuse/datastructure"
	"notabug.org/apiote/amuse/i18n"
	"notabug.org/apiote/amuse/tmdb"
	"notabug.org/apiote/amuse/wikidata"

	"bytes"
	"golang.org/x/text/language"
	"html/template"
	"log"
	"strings"
	"time"

	"github.com/pquerna/otp"
)

type RenderData struct {
	Data    interface{}
	Strings i18n.Translation
	State   struct {
		Error error
		User  accounts.User
	}
}

func (d RenderData) LetAmuse0() string {
	let_amuse := strings.Split(d.Strings.Index["let_amuse_you"], "{}")
	let_amuse[0], let_amuse[1] = strings.Trim(let_amuse[0], " "), strings.Trim(let_amuse[1], " ")
	return let_amuse[0]
}

func (d RenderData) LetAmuse1() string {
	let_amuse := strings.Split(d.Strings.Index["let_amuse_you"], "{}")
	let_amuse[0], let_amuse[1] = strings.Trim(let_amuse[0], " "), strings.Trim(let_amuse[1], " ")
	return let_amuse[1]
}

func (d RenderData) GetPremiereType(index int) string {
	return i18n.GetPremiereType(index, d.Strings)
}

func (d RenderData) FormatDate(date time.Time) string {
	return i18n.FormatDate(date, d.Strings.Global["date_format"], d.Strings.Global)
}

func (d RenderData) FormatDateNice(date time.Time, timezone string) string {
	return i18n.FormatDateNice(date, d.Strings, timezone)
}

func (d RenderData) RenderAsciiDoc(s string) template.HTML {
	return i18n.RenderAsciiDoc(s)
}

func (d RenderData) GetErrorData(code int, kind string) string {
	return i18n.GetErrorData(code, d.Strings, kind)
}

type HtmlRenderer struct {
	user accounts.User
}

func render(languages []language.Tag, data RenderData, file string) string {
	err := i18n.LoadServerLangs()
	if err != nil {
		// todo return http:500
	}
	language, err := i18n.Match(languages)
	if err != nil {
		// todo return http:500
	}
	strings, err := i18n.LoadStrings(language)
	if err != nil {
		// todo return http:500
	}

	data.Strings = strings

	t, err := template.ParseFiles(config.DataHome + "/templates/" + file + ".html")
	if err != nil {
		log.Println(err)
		// todo return http:500
	}
	b := bytes.NewBuffer([]byte{})
	err = t.Execute(b, data)
	if err != nil {
		log.Println(err)
		// todo return http:500
	}
	return b.String()
}

func (r HtmlRenderer) RenderFilm(film *tmdb.Film, languages []language.Tag) string {
	data := RenderData{Data: film}
	data.State.User = r.user
	return render(languages, data, "film")
}

func (r HtmlRenderer) RenderSearch(tmdbResults *tmdb.SearchResults, inventaireResults *wikidata.SearchResults, languages []language.Tag) string {
	results := struct {
		T *tmdb.SearchResults
		I *wikidata.SearchResults
	}{tmdbResults, inventaireResults}
	data := RenderData{Data: results}
	data.State.User = r.user
	return render(languages, data, "search")
}

func (r HtmlRenderer) RenderIndex(randomComedy string, languages []language.Tag) string {
	data := RenderData{Data: randomComedy}
	data.State.User = r.user
	return render(languages, data, "index")
}

func (r HtmlRenderer) RenderTvSerie(tvSerie *tmdb.TvSerie, languages []language.Tag) string {
	data := RenderData{Data: tvSerie}
	data.State.User = r.user
	return render(languages, data, "tvserie")
}

func (r HtmlRenderer) RenderPerson(person *tmdb.Person, languages []language.Tag) string {
	data := RenderData{Data: person}
	data.State.User = r.user
	return render(languages, data, "person")
}

func (r HtmlRenderer) RenderBook(book datastructure.Book, languages []language.Tag) string {
	data := RenderData{Data: book}
	data.State.User = r.user
	return render(languages, data, "book")
}

func (r HtmlRenderer) RenderBookSerie(bookSerie wikidata.BookSerie, languages []language.Tag) string {
	data := RenderData{Data: bookSerie}
	data.State.User = r.user
	return render(languages, data, "bookserie")
}

func (r HtmlRenderer) RenderAbout(languages []language.Tag) string {
	data := RenderData{}
	data.State.User = r.user
	return render(languages, data, "about")
}

func (HtmlRenderer) RenderErrorPage(code int, err error, languages []language.Tag) string {
	e := struct {
		Code         int
		User         string
		ItemType     string
		ItemID       string
		IsOnWantList bool
	}{
		Code: code,
	}
	if tmdbNotFountError, ok := err.(tmdb.NotFountError); ok {
		e.User = tmdbNotFountError.User
		e.ItemType = tmdbNotFountError.ItemType
		e.ItemID = tmdbNotFountError.ItemID
		e.IsOnWantList = tmdbNotFountError.IsOnWantList
	}
	data := RenderData{Data: e}
	return render(languages, data, "error")
}

func (HtmlRenderer) RenderLogin(languages []language.Tag, authError error, target string) string {
	data := RenderData{Data: target}
	data.State.Error = authError
	return render(languages, data, "login")
}

func (HtmlRenderer) RenderLoggedOut(languages []language.Tag) string {
	data := RenderData{}
	return render(languages, data, "loggedout")
}

func (HtmlRenderer) RenderSignup(languages []language.Tag, authError error, key *otp.Key, sfaEnabled bool, username, qr string) string {
	secret := struct {
		Secret     string
		SfaEnabled bool
		Username   string
		Qr         template.URL
	}{key.Secret(), sfaEnabled, username, template.URL(qr)}
	data := RenderData{Data: secret}
	data.State.Error = authError

	var template string
	if config.OpenRegistration {
		template = "signup"
	} else {
		template = "signup_locked"
	}

	return render(languages, data, template)
}

func (r HtmlRenderer) RenderSignedup(languages []language.Tag, recoveryCodes []string) string {
	data := RenderData{Data: recoveryCodes}
	data.State.User = r.user
	return render(languages, data, "signedup")
}

func (r HtmlRenderer) RenderWatchlist(watchlist datastructure.Watchlist, languages []language.Tag) string {
	data := RenderData{Data: watchlist}
	data.State.User = r.user
	return render(languages, data, "watchlist")
}

func (r HtmlRenderer) RenderTvQueue(tvqueue datastructure.TvQueue, languages []language.Tag) string {
	data := RenderData{Data: tvqueue}
	data.State.User = r.user
	return render(languages, data, "tvqueue")
}

func (r HtmlRenderer) RenderReadlist(readlist datastructure.Readlist, languages []language.Tag) string {
	data := RenderData{Data: readlist}
	data.State.User = r.user
	return render(languages, data, "readlist")
}

func (r HtmlRenderer) RenderExperiences(experiences datastructure.Experiences, languages []language.Tag) string {
	data := RenderData{Data: experiences}
	data.State.User = r.user
	return render(languages, data, "experiences")
}

func (r HtmlRenderer) RenderAccount(user accounts.User, languages []language.Tag) string {
	data := RenderData{Data: user}
	data.State.User = r.user
	return render(languages, data, "account")
}
