package app

import (
	
	
)

// Page is the interface that describes a web page.
type Page interface {
	// Returns the page title.
	Title() string

	// Sets the page title.
	SetTitle(format string, v ...any)

	// Returns the page language.
	Lang() string

	// Set the page language.
	SetLang(v string)

	// Returns the page description.
	Description() string

	// Sets the page description.
	SetDescription(format string, v ...any)

	// Returns the page author.
	Author() string

	// Sets the page author.
	SetAuthor(format string, v ...any)

	// Returns the page keywords.
	Keywords() string

	// Sets the page keywords.
	SetKeywords(v ...string)

	// Returns the page resources to preload.
	Preloads() []Preload

	// Sets resources to preload.
	SetPreloads(v ...Preload)

	// Set the page loading label.
	SetLoadingLabel(format string, v ...any)

	// Returns the image used by social networks when linking the page.
	Image() string

	// Set the image used by social networks when linking the page.
	SetImage(v string)

	// Returns the page URL.
	URL() *url.URL

	// Replace the the current page URL by the given one in the browser history.
	//
	// Does not work when pre-rendering.
	ReplaceURL(v *url.URL)

	// Returns the page width and height in px.
	Size() (w int, h int)

	// Set the Twitter card.
	SetTwitterCard(v TwitterCard)

	// Set the page's canonical link.
	SetCanonicalLink(format string, v ...any)
}

type requestPage struct {
	url        *url.URL
	resolveURL func(string) string

	title          string
	lang           string
	description    string
	author         string
	keywords       string
	preloads       []Preload
	loadingLabel   string
	image          string
	canonicalLink  string
	width          int
	height         int
	twitterCardMap map[string]string
}

func makeRequestPage( *url.URL,  func(string) string) requestPage {
	return requestPage{
		url:        ,
		resolveURL: ,
	}
}

func ( *requestPage) () string {
	return .title
}

func ( *requestPage) ( string,  ...any) {
	.title = FormatString(, ...)
}

func ( *requestPage) () string {
	return .lang
}

func ( *requestPage) ( string) {
	.lang = 
}

func ( *requestPage) () string {
	return .description
}

func ( *requestPage) ( string,  ...any) {
	.description = FormatString(, ...)
}

func ( *requestPage) () string {
	return .author
}

func ( *requestPage) ( string,  ...any) {
	.author = FormatString(, ...)
}

func ( *requestPage) () string {
	return .keywords
}

func ( *requestPage) ( ...string) {
	.keywords = strings.Join(, ", ")
}

func ( *requestPage) () []Preload {
	return .preloads
}

func ( *requestPage) ( ...Preload) {
	for ,  := range  {
		[].Href = .resolveURL(.Href)
	}
	.preloads = 
}

func ( *requestPage) ( string,  ...any) {
	.loadingLabel = FormatString(, ...)
}

func ( *requestPage) () string {
	return .image
}

func ( *requestPage) ( string) {
	if  != "" {
		.image = .resolveURL()
	}
}

func ( *requestPage) () *url.URL {
	return .url
}

func ( *requestPage) ( *url.URL) {
	.url = 
}

func ( *requestPage) () ( int,  int) {
	return .width, .height
}

func ( *requestPage) ( TwitterCard) {
	.Image = .resolveURL(.Image)
	.twitterCardMap = .toMap()
}

func ( *requestPage) ( string,  ...any) {
	if  := FormatString(, ...);  != "" {
		.canonicalLink = .resolveURL()
	}
}

type browserPage struct {
	resolveURL func(string) string
}

func makeBrowserPage( func(string) string) browserPage {
	return browserPage{resolveURL: }
}

func ( browserPage) () string {
	return Window().
		Get("document").
		Get("title").
		String()
}

func ( browserPage) ( string,  ...any) {
	 := FormatString(, ...)
	Window().Get("document").Set("title", )
	.metaByProperty("og:title").setAttr("content", )
}

func ( browserPage) () string {
	return Window().
		Get("document").
		Get("documentElement").
		Get("lang").
		String()
}

func ( browserPage) ( string) {
	Window().
		Get("document").
		Get("documentElement").
		Set("lang", )
}

func ( browserPage) () string {
	return .metaByName("description").getAttr("content")
}

func ( browserPage) ( string,  ...any) {
	 := FormatString(, ...)
	.metaByName("description").setAttr("content", )
	.metaByProperty("og:description").setAttr("content", )
}

func ( browserPage) () string {
	return .metaByName("author").getAttr("content")
}

func ( browserPage) ( string,  ...any) {
	.metaByName("author").setAttr("content", FormatString(, ...))
}

func ( browserPage) () string {
	return .metaByName("keywords").getAttr("content")
}

func ( browserPage) ( ...string) {
	.metaByName("keywords").setAttr("content", strings.Join(, ", "))
}

func ( browserPage) ( string,  ...any) {
}

func ( browserPage) () []Preload {
	return nil
}

func ( browserPage) ( ...Preload) {
}

func ( browserPage) () string {
	return .metaByProperty("og:image").getAttr("content")
}

func ( browserPage) ( string) {
	if  != "" {
		.metaByProperty("og:image").setAttr("content", .resolveURL())
	}
}

func ( browserPage) () *url.URL {
	return Window().URL()
}

func ( browserPage) ( *url.URL) {
	Window().replaceHistory()
	.metaByProperty("og:url").setAttr("content", .String())
}

func ( browserPage) () ( int,  int) {
	return Window().Size()
}

func ( browserPage) ( TwitterCard) {
	.Image = .resolveURL(.Image)
	 := Window().Get("document").Get("head")

	for ,  := range .toMap() {
		if  == "" {
			continue
		}
		,  := Window().createElement("meta", "")
		.setAttr("name", )
		.setAttr("content", )
		.appendChild()
	}
}

func ( browserPage) ( string,  ...any) {
}

func ( browserPage) ( string) Value {
	 := Window().
		Get("document").
		Call("querySelector", "meta[name='"++"']")

	if .IsNull() {
		, _ = Window().createElement("meta", "")
		.setAttr("name", )

		Window().Get("document").
			Get("head").
			appendChild()
	}

	return 
}

func ( browserPage) ( string) Value {
	 := Window().
		Get("document").
		Call("querySelector", "meta[property='"++"']")

	if .IsNull() {
		, _ = Window().createElement("meta", "")
		.setAttr("property", )

		Window().Get("document").
			Get("head").
			appendChild()
	}

	return 
}

type Preload struct {
	Type          string
	As            string
	Href          string
	FetchPriority string
}