package tmdb

import (
	"notabug.org/apiote/amuse/utils"
	"notabug.org/apiote/gott"

	"encoding/json"
	"net/http"
	"net/url"
	"time"
)

type SearchResults struct {
	Query       string
	Page        int
	Total_pages int `json:"total_pages"`
	Results     []struct {
		Id                 int
		Media_type         string `json:"media_type"`
		Name               string
		Title              string
		First_air_date_str string `json:"first_air_date"`
		Release_date_str   string `json:"release_date"`
		Poster_path        string `json:"poster_path"`
		Profile_path       string `json:"profile_path"`
		Release_date       time.Time
	}
}

func (r SearchResults) NextPage() int {
	return r.Page + 1
}

func (r SearchResults) PrevPage() int {
	return r.Page - 1
}

type TmdbQuery struct {
	query    string
	language string
	page     string
}

func createSearchQuery(args ...interface{}) (interface{}, error) {
	tmdbQuery := args[0].(TmdbQuery)
	client := &http.Client{}
	url :="https://api.themoviedb.org/3/search/multi?api_key="+API_KEY+"&language="+tmdbQuery.language+"&query="+url.QueryEscape(tmdbQuery.query)+"&page="+tmdbQuery.page+"&include_adult=false"
	request, err := http.NewRequest("GET", url, nil)
	args[1] = client
	args[2] = request
	return gott.Tuple(args), err
}

func doQuery(args ...interface{}) (interface{}, error) { // note can be doRequest if we abstractise adding headers
	client := args[1].(*http.Client)
	request := args[2].(*http.Request)
	resp, err := client.Do(request)
	args[3] = resp
	return gott.Tuple(args), err
}

func unmarshalSearchResults(args ...interface{}) (interface{}, error) {
	tmdbQuery := args[0].(TmdbQuery)
	body := []byte(args[3].(string))
	results := &SearchResults{}
	err := json.Unmarshal(body, results)
	results.Query = tmdbQuery.query
	for i, result := range results.Results {
		if result.Name == "" {
			result.Name = result.Title
		}
		if result.Poster_path == "" {
			result.Poster_path = result.Profile_path
		}
		results.Results[i] = result
	}
	args[3] = results
	return gott.Tuple(args), err
}

func convertSearchResultsDates(args ...interface{}) (interface{}, error) {
	results := args[3].(*SearchResults)
	var err error = nil
	for i, result := range results.Results {
		if result.Release_date_str != "" {
			date, err2 := time.Parse("2006-01-02", result.Release_date_str)
			result.Release_date = date
			err = utils.Or(err2, err)
			results.Results[i] = result
		}
		if result.First_air_date_str != "" {
			date, err2 := time.Parse("2006-01-02", result.First_air_date_str)
			result.Release_date = date
			err = utils.Or(err2, err)
			results.Results[i] = result
		}
	}
	args[3] = results
	return gott.Tuple(args), err
}

func Search(query, language, page string) (*SearchResults, error) {
	// todo later add books
	results, err := gott.
		NewResult(gott.Tuple{TmdbQuery{query, language, page}, nil, nil, nil, nil}).
		// todo parse query -> search (when no nigmas) |-> discover (when nigmas)
		Bind(createSearchQuery).
		Bind(doQuery).
		Bind(handleRequestError).
		Bind(readResponse).
		Bind(unmarshalSearchResults).
		Bind(convertSearchResultsDates).
		Finish()

	if err != nil {
		return &SearchResults{}, err
	} else {
		return results.(gott.Tuple)[3].(*SearchResults), nil
	}
}
