package api

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"

	"github.com/juju/errors"
	"github.com/machinebox/graphql"
	"github.com/pingcap/log"
	"go.uber.org/zap"
)

type DatasetSearchResult struct {
	Search struct {
		Start         int `json:"start"`
		Count         int `json:"count"`
		Total         int `json:"total"`
		SearchResults []struct {
			Entity struct {
				URN  string `json:"urn"`
				Type string `json:"type"`
				Name string `json:"name"`
			} `json:"entity"`
		} `json:"searchResults"`
	} `json:"search"`
}

func (d *DatasetSearchResult) String() string {
	rawBytes, err := json.Marshal(d)
	if err != nil {
		return ""
	}

	return string(rawBytes)
}

/*func (cli *DatahubClient) SearchDatasetUrn(project, dataset string) (string, error) {
	//query = `{"query":"{\n\tsearch(input: { type: DATASET, query: \"salesforce.crm_account\", start: 0, count: 10 }) {\n\t  start\n\t  count\n\t  total\n\t  searchResults {\n\t\tentity {\n\t\t   urn\n\t\t   type\n\t\t   ...on Dataset {\n\t\t\t  name\n\t\t   }\n\t\t}\n\t  }\n\t}\n  }"}`
	// Set the GraphQL query string
	query := fmt.Sprintf(`{"query":"{\n\tsearch(input: { type: DATASET, query: \"%s\", start: 0, count: 10 }) {\n\t  start\n\t  count\n\t  total\n\t  searchResults {\n\t\tentity {\n\t\t   urn\n\t\t   type\n\t\t   ...on Dataset {\n\t\t\t  name\n\t\t   }\n\t\t}\n\t  }\n\t}\n  }"}`, dataset)
	var data = &DatasetSearchResult{}
	err := cli.doRquest(query, data)
	if err != nil {
		return "", errors.Annotatef(err, "fail to search dataset %s", dataset)
	}

	// find dataset name in data equal to dataset
	for _, result := range data.Data.Search.SearchResults {
		if strings.HasPrefix(result.Entity.Name, project) && strings.HasSuffix(result.Entity.Name, dataset) {
			return result.Entity.URN, nil
		}
	}

	return "", errors.NotFoundf("project %s dataset %s", project, dataset)
}*/

func (cli *DatahubClient) SearchDatasetUrn(project, dataset string) (string, error) {
	// Set up the client
	graphqlCli := graphql.NewClient(cli.APIEndpoint)

	/*filter := map[string]interface{}{
		"and": map[string]interface{}{
			"field": "tags", "condition": "CONTAIN", "negated": true, "values": "metagen",
		},
	}*/
	var filter map[string]interface{}

	// Set up the query
	req := graphql.NewRequest(`
			query ($query: String!, $filter: [AndFilterInput!]){
				search(input: { type: DATASET, query: $query, start: 0, count: 10, orFilters: $filter}) {
					start
					count
					total
					searchResults {
					  	entity {
							urn
						 	type
						 	...on Dataset {
								name
						 	}
					  	}
					}
				}
			}
		`)
	req.Var("filter", filter)
	req.Var("query", dataset)
	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", cli.token))

	// Send the query to the server
	ctx := context.Background()
	//var respData map[string]interface{}
	var respData DatasetSearchResult
	if err := graphqlCli.Run(ctx, req, &respData); err != nil {
		return "", errors.Annotatef(err, "fail to search dataset %s", dataset)
	}

	log.Debug("query result", zap.Any("result", respData))

	// find dataset name in data equal to dataset
	for _, result := range respData.Search.SearchResults {
		if strings.HasPrefix(result.Entity.Name, project) && strings.HasSuffix(result.Entity.Name, dataset) {
			return result.Entity.URN, nil
		}
	}

	return "", errors.NotFoundf("project %s dataset %s", project, dataset)
}
