package wikidata

import (
	"strings"

	"notabug.org/apiote/amuse/network"

	"encoding/json"
	"math"
	"net/http"
	"net/url"
	"strconv"

	"notabug.org/apiote/gott"
)

type SearchResults struct {
	Results []struct {
		Id          string
		Type        string
		Uri         string
		Label       string
		Description string
		Image       string
		ImagePath   string
	}
}

type WikidataQuery struct {
	query    string
	language string
	page     int64
}

func createSearchQuery(args ...interface{}) (interface{}, error) {
	query := args[0].(*WikidataQuery)
	result := args[1].(*network.Result)
	client := &http.Client{}
	url := "https://inventaire.io/api/search?types=works|series&lang=" + query.language + "&search=" + url.QueryEscape(query.query) + "&limit=" + strconv.FormatInt(8*(query.page+1), 10)
	request, err := http.NewRequest("GET", url, nil)
	result.Client = client
	result.Request = request
	return gott.Tuple(args), err
}

func unmarshalSearchResults(args ...interface{}) (interface{}, error) {
	query := args[0].(*WikidataQuery)
	result := args[1].(*network.Result)
	results := &SearchResults{}
	err := json.Unmarshal(result.Body, results)
	fisrtOnPage := int(query.page * 8)
	if len(results.Results) > fisrtOnPage {
		firstOnNext := math.Min(float64(query.page+1)*8, float64(len(results.Results)))
		results.Results = results.Results[fisrtOnPage:int(firstOnNext)]
	}
	result.Result = results
	return gott.Tuple(args), err
}

func parseImageUri(args ...interface{}) interface{} {
	results := args[1].(*network.Result).Result.(*SearchResults)
	for i, result := range results.Results {
		if !strings.Contains(result.Image, "/img/entities") {
			result.ImagePath = ""
		} else {
			result.ImagePath = "https://inventaire.io" + result.Image
		}
		results.Results[i] = result
	}
	return gott.Tuple(args)
}

func Search(query, language string, page int64) (*SearchResults, error) {
	results, err := gott.
		NewResult(gott.Tuple{&WikidataQuery{query, language, page}, &network.Result{}}).
		Bind(createSearchQuery).
		Bind(network.DoRequest).
		Bind(network.HandleRequestError).
		Bind(network.ReadResponse).
		Bind(unmarshalSearchResults).
		Map(parseImageUri).
		Finish()

	if err != nil {
		if _, ok := err.(network.HttpError); ok {
			return &SearchResults{}, nil
		}
		return &SearchResults{}, err
	} else {
		return results.(gott.Tuple)[1].(*network.Result).Result.(*SearchResults), nil
	}
}
