package shop

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strings"
)

type ShopMatch struct {
	Image       string `json:"image"`
	ImageHeight int64  `json:"image_height"`
	ImageWidth  int64  `json:"image_width"`
	URL         string `json:"url"`
	Price       string `json:"price"`
	Title       string `json:"title"`
}

type ScrapelessShopMatch struct {
	Currency        string `json:"currency"`
	ExtractedPrice  int64  `json:"extracted_price"`
	Image           string `json:"image"`
	ImageHeight     int64  `json:"image_height"`
	ImageWidth      int64  `json:"image_width"`
	Link            string `json:"link"`
	Position        int64  `json:"position"`
	Price           string `json:"price"`
	Source          string `json:"source"`
	SourceIcon      string `json:"source_icon"`
	InStock         string `json:"stock_information"`
	Thumbnail       string `json:"thumbnail"`
	ThumbnailHeight int64  `json:"thumbnail_height"`
	ThumbnailWidth  int64  `json:"thumbnail_width"`
	Title           string `json:"title"`
}

type ScrapingDogShopMatch struct {
	Title             string `json:"title"`
	Link              string `json:"link"`
	OriginalThumbnail string `json:"original_thumbnail"`
	Thumbnail         string `json:"thumbnail"`
	Tag               string `json:"tag"`
}

// shop - scraping dog version
func ShopGoogleLensDog(imageUrl string, countryCode string, languageCode string) (error, []ShopMatch) {
	//testurl := "https://editor.remodelai.app/assets/assets/samples/03-living-room.jpg"
	fullurl := fmt.Sprintf("https://api.scrapingdog.com/google_lens?api_key=%s&product=true&url=%s&country=us", "6823d872ebcd73e5bf7e6599", url.QueryEscape(imageUrl))

	req, err := http.NewRequest("GET", fullurl, nil)
	if err != nil {
		log.Printf("Error: ScrapingDog new request: %v\n", err)
		return fmt.Errorf("Shop failed - request error"), nil
	}

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Printf("Error: ScrapingDog request: %v\n", err)
		return fmt.Errorf("Shop failed - request error"), nil
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Printf("Error: ScrapingDog read response: %v\n", err)
		return fmt.Errorf("Shop failed - read error"), nil
	}
	var responseJson map[string]interface{}
	err = json.Unmarshal(body, &responseJson)
	if err != nil {
		log.Printf("Error: ScrapingDog invalid response: %v: \"%20v\" \n", err, body)
		return fmt.Errorf("Shop failed - invalid response"), nil
	}
	matches, ok := responseJson["lens_results"]
	if !ok {
		return fmt.Errorf("Shop failed - no items found"), nil
	}
	visualMatches, ok := matches.([]interface{})
	if !ok {
		return fmt.Errorf("Shop failed - invalid items found"), nil
	}
	visualMatchesBytes, err := json.Marshal(visualMatches)
	if err != nil {
		log.Printf("Error: ScrapingDog invalid visual_matches %v\n", err)
		return fmt.Errorf("Shop failed - invalid matches"), nil
	}
	if strings.Contains(string(visualMatchesBytes), "Google Lens didn't return any results.") {
		log.Printf("Alert: No shopping results found.")
		//return fmt.Errorf("No shopping results found"), nil
		return nil, make([]ShopMatch, 0)
	}
	var matchlist []ScrapingDogShopMatch
	err = json.Unmarshal(visualMatchesBytes, &matchlist)
	if err != nil {
		log.Printf("Error: Invalid match: %v %v\n", err, string(visualMatchesBytes))
		return fmt.Errorf("Shop failed - invalid match"), nil
	}
	var finalList []ShopMatch
	for i := 0; i < len(matchlist); i++ {
		finalList = append(finalList, convertScrapingDog(matchlist[i]))
	}

	return nil, finalList
}

// shop - scrapeless version
func ShopGoogleLens(imageUrl string, countryCode string, languageCode string) (error, []ShopMatch) {
	scrapelessurl := "https://api.scrapeless.com/api/v1/scraper/request"
	token := "sk_OLy5fVl4M8UYBYrrbO1lQwaxEArNIWaY20aVUScy010zqsbxub53Qz7wzwOYSVib"
	headers := map[string]string{"x-api-token": token}

	basePayload := `{
    "actor": "scraper.google.lens",
    "input": {
        "url": "%s",
        "hl": "%s",
        "gl": "%s",
        "direct_link": "True",
        "search_type": "products"
    }
  }`
	payloadString := fmt.Sprintf(basePayload, imageUrl, languageCode, countryCode)

	req, err := http.NewRequest("POST", scrapelessurl, bytes.NewBuffer([]byte(payloadString)))
	if err != nil {
		log.Printf("Error: Scrapeless new request: %v\n", err)
		return fmt.Errorf("Shop failed - request error"), nil
	}

	for key, value := range headers {
		req.Header.Set(key, value)
	}

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Printf("Error: Scrapeless request: %v\n", err)
		return fmt.Errorf("Shop failed - request error"), nil
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Printf("Error: Scrapeless read response: %v\n", err)
		return fmt.Errorf("Shop failed - read error"), nil
	}
	var responseJson map[string]interface{}
	err = json.Unmarshal(body, &responseJson)
	if err != nil {
		log.Printf("Error: Scrapeless invalid response: %v\n", err)
		return fmt.Errorf("Shop failed - invalid response"), nil
	}
	matches, ok := responseJson["visual_matches"]
	if !ok {
		return fmt.Errorf("Shop failed - no items found"), nil
	}
	visualMatches, ok := matches.([]interface{})
	if !ok {
		return fmt.Errorf("Shop failed - invalid items found"), nil
	}
	visualMatchesBytes, err := json.Marshal(visualMatches)
	if err != nil {
		log.Printf("Error: Scrapeless invalid visual_matches %v\n", err)
		return fmt.Errorf("Shop failed - invalid matches"), nil
	}
	if strings.Contains(string(visualMatchesBytes), "Google Lens didn't return any results.") {
		log.Printf("Alert: No shopping results found.")
		//return fmt.Errorf("No shopping results found"), nil
		return nil, make([]ShopMatch, 0)
	}
	var matchlist []ScrapelessShopMatch
	err = json.Unmarshal(visualMatchesBytes, &matchlist)
	if err != nil {
		log.Printf("Error: Invalid match: %v %v\n", err, string(visualMatchesBytes))
		return fmt.Errorf("Shop failed - invalid match"), nil
	}
	var finalList []ShopMatch
	for i := 0; i < len(matchlist); i++ {
		finalList = append(finalList, convertScrapeless(matchlist[i]))
	}

	return nil, finalList
}

func convertScrapeless(match ScrapelessShopMatch) ShopMatch {
	var newMatch ShopMatch
	newMatch.Image = match.Image
	newMatch.ImageWidth = match.ImageWidth
	newMatch.ImageHeight = match.ImageHeight
	newMatch.URL = match.Link
	newMatch.Price = match.Price
	newMatch.Title = match.Title
	return newMatch
}

func convertScrapingDog(match ScrapingDogShopMatch) ShopMatch {
	var newMatch ShopMatch
	newMatch.Title = match.Title
	newMatch.Image = match.Thumbnail
	newMatch.URL = match.Link
	newMatch.Price = match.Tag
	return newMatch
}
