package query

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"

	"git.yetaga.in/alazyreader/library/media"
)

type GoogleBooks struct{}

type googleBookResult struct {
	Kind       string `json:"kind"`
	TotalItems int    `json:"totalItems"`
	Items      []item `json:"items"`
}

type industryIdentifier struct {
	Type       string `json:"type"`
	Identifier string `json:"identifier"`
}

type readingMode struct {
	Text  bool `json:"text"`
	Image bool `json:"image"`
}

type panelizationSummary struct {
	ContainsEpubBubbles  bool `json:"containsEpubBubbles"`
	ContainsImageBubbles bool `json:"containsImageBubbles"`
}

type imageLink struct {
	SmallThumbnail string `json:"smallThumbnail"`
	Thumbnail      string `json:"thumbnail"`
}

type volumeInfo struct {
	Title               string               `json:"title"`
	Subtitle            string               `json:"subtitle"`
	Authors             []string             `json:"authors"`
	Publisher           string               `json:"publisher"`
	PublishedDate       string               `json:"publishedDate"`
	Description         string               `json:"description"`
	IndustryIdentifiers []industryIdentifier `json:"industryIdentifiers"`
	ReadingModes        readingMode          `json:"readingModes"`
	PageCount           int                  `json:"pageCount"`
	PrintType           string               `json:"printType"`
	Categories          []string             `json:"categories"`
	AverageRating       float64              `json:"averageRating"`
	RatingsCount        int                  `json:"ratingsCount"`
	MaturityRating      string               `json:"maturityRating"`
	AllowAnonLogging    bool                 `json:"allowAnonLogging"`
	ContentVersion      string               `json:"contentVersion"`
	PanelizationSummary panelizationSummary  `json:"panelizationSummary"`
	ImageLinks          imageLink            `json:"imageLinks"`
	Language            string               `json:"language"`
	PreviewLink         string               `json:"previewLink"`
	InfoLink            string               `json:"infoLink"`
	CanonicalVolumeLink string               `json:"canonicalVolumeLink"`
}

type saleInfo struct {
	Country     string `json:"country"`
	Saleability string `json:"saleability"`
	IsEbook     bool   `json:"isEbook"`
}

type epub struct {
	IsAvailable bool `json:"isAvailable"`
}

type pdf struct {
	IsAvailable bool `json:"isAvailable"`
}

type accessInfo struct {
	Country                string `json:"country"`
	Viewability            string `json:"viewability"`
	Embeddable             bool   `json:"embeddable"`
	PublicDomain           bool   `json:"publicDomain"`
	TextToSpeechPermission string `json:"textToSpeechPermission"`
	Epub                   epub   `json:"epub"`
	Pdf                    pdf    `json:"pdf"`
	WebReaderLink          string `json:"webReaderLink"`
	AccessViewStatus       string `json:"accessViewStatus"`
	QuoteSharingAllowed    bool   `json:"quoteSharingAllowed"`
}

type searchInfo struct {
	TextSnippet string `json:"textSnippet"`
}

type item struct {
	Kind       string     `json:"kind"`
	ID         string     `json:"id"`
	Etag       string     `json:"etag"`
	SelfLink   string     `json:"selfLink"`
	VolumeInfo volumeInfo `json:"volumeInfo"`
	SaleInfo   saleInfo   `json:"saleInfo"`
	AccessInfo accessInfo `json:"accessInfo"`
	SearchInfo searchInfo `json:"searchInfo"`
}

func (g *GoogleBooks) GetByISBN(isbn string) (*media.Book, error) {
	client := &http.Client{}
	resp, err := client.Get(fmt.Sprintf("https://www.googleapis.com/books/v1/volumes?q=isbn:%s", isbn))

	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("received non-200 status code: %d", resp.StatusCode)
	}

	var result googleBookResult
	b, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if err = json.Unmarshal(b, &result); err != nil {
		return nil, err
	}

	if len(result.Items) == 0 {
		return nil, fmt.Errorf("no book found")
	}

	return googleToBook(result.Items[0]), nil
}

func googleToBook(i item) *media.Book {
	return &media.Book{
		Title:       buildTitle(i.VolumeInfo.Title, i.VolumeInfo.Subtitle),
		Authors:     i.VolumeInfo.Authors,
		SortAuthor:  strings.ToLower(getLastName(tryGetFirst(i.VolumeInfo.Authors))),
		ISBN10:      getIdentifierType(i.VolumeInfo.IndustryIdentifiers, "ISBN_10"),
		ISBN13:      getIdentifierType(i.VolumeInfo.IndustryIdentifiers, "ISBN_13"),
		Publisher:   i.VolumeInfo.Publisher,
		Year:        strings.Split(i.VolumeInfo.PublishedDate, "-")[0],
		Description: i.VolumeInfo.Description,
		Genre:       tryGetFirst(i.VolumeInfo.Categories),
	}
}

func getIdentifierType(iis []industryIdentifier, typename string) string {
	for _, ident := range iis {
		if ident.Type == typename {
			return ident.Identifier
		}
	}
	return ""
}
