package libamuse

import (
	"notabug.org/apiote/amuse/accounts"
	"notabug.org/apiote/amuse/datastructure"
	"notabug.org/apiote/amuse/db"
	"notabug.org/apiote/amuse/tmdb"

	"strconv"
	"time"

	"notabug.org/apiote/gott"
)

func getFilm(args ...interface{}) (interface{}, error) {
	data := args[0].(*RequestData)
	result := args[1].(*Result)
	languages := result.languages
	film, err := tmdb.GetFilm(data.id, languages[0].String())
	result.result = film
	if err != nil {
		if e, ok := err.(tmdb.NotFountError); ok {
			e.User = result.user.Username
			err = e
		}
	}
	return gott.Tuple(args), err
}

func getCollection(args ...interface{}) (interface{}, error) {
	result := args[1].(*Result)
	film := result.result.(*tmdb.Film)
	languages := result.languages
	var err error
	if film.Collection.Id != 0 {
		collection, e := tmdb.GetCollection(
			strconv.FormatInt(int64(film.Collection.Id), 10),
			languages[0].String())
		film.Collection = *collection
		err = e
	}
	return gott.Tuple(args), err
}

func getCollectionWatches(args ...interface{}) (interface{}, error) {
	result := args[1].(*Result)
	film := result.result.(*tmdb.Film)

	if result.user.IsEmpty() {
		return gott.Tuple(args), nil
	}

	for i, part := range film.Collection.Parts {
		experiences, err := db.GetItemExperiences(result.user.Username, strconv.FormatInt(int64(part.Id), 10), datastructure.ItemTypeFilm)
		if err != nil {
			return gott.Tuple(args), err
		}
		if len(experiences) > 0 {
			part.IsWatched = true
			film.Collection.Parts[i] = part
		}
	}
	return gott.Tuple(args), nil
}

func addToCalendar(args ...interface{}) error {
	var (
		err  error
		date time.Time
	)
	result := args[1].(*Result)
	film := result.result.(*tmdb.Film)
	user := result.user
	if user.AutoCalendar && film.IsOnWantList {
		releases := film.ReleaseDates[user.Country]
		for _, release := range releases {
			if release.Type == tmdb.PREMIERE_TYPE_CINEMA {
				date = release.ReleaseDate
				break
			}
		}
		if !date.IsZero() {
			err = db.AddToCalendar(user.Username, film.Title, date, film.Id, tmdb.PREMIERE_TYPE_CINEMA)
			if err != nil {
				return err
			}
		}
		for _, release := range film.EarliestReleaseDates {
			if release.Type == tmdb.PREMIERE_TYPE_DIGITAL {
				date = release.ReleaseDate
				break
			}
		}
		if !date.IsZero() {
			err = db.AddToCalendar(user.Username, film.Title, date, film.Id, tmdb.PREMIERE_TYPE_DIGITAL)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func renderFilm(args ...interface{}) interface{} {
	result := args[1].(*Result)
	film := result.result.(*tmdb.Film)
	result.page = result.renderer.RenderFilm(film, result.languages)
	return gott.Tuple(args)
}

func getFilmExperiences(args ...interface{}) (interface{}, error) {
	data := args[0].(*RequestData)
	result := args[1].(*Result)
	film := result.result.(*tmdb.Film)

	if result.user.IsEmpty() {
		return gott.Tuple(args), nil
	}

	exp, err := db.GetItemExperiences(result.user.Username, data.id, datastructure.ItemTypeFilm)
	film.Experiences = exp[data.id]
	return gott.Tuple(args), err
}

func ShowFilm(id, language, mimetype string, auth accounts.Authentication) (string, error) {
	auth.Necessary = false
	request := &RequestData{id: id, language: language, mimetype: mimetype, auth: auth}
	r, err := gott.
		NewResult(gott.Tuple{request, &Result{}}).
		Bind(parseLanguage).
		Bind(verifyToken).
		Bind(getFilm).
		Bind(getCollection).
		Bind(getCollectionWatches).
		Bind(getBasedOn).
		Bind(updateCache).
		Bind(getFilmExperiences).
		Bind(isOnWantList).
		Tee(addToCalendar).
		Bind(createRenderer).
		Map(renderFilm).
		Finish()

	if err != nil {
		return "", err
	} else {
		return r.(gott.Tuple)[1].(*Result).page, nil
	}
}
