package compiler

// import (
// 	"errors"
// 	"fmt"
// 	"log"
// 	"time"

// 	"go.kuoruan.net/v8go-polyfills/console"
// 	"go.kuoruan.net/v8go-polyfills/fetch"
// 	"rogchap.com/v8go"
// )

import (
	"esperframework/compiler/appshell"
	"esperframework/compiler/parser"
	"esperframework/options"
	"esperframework/utils"
	"path/filepath"
	"strings"
	"unicode"
)

func aggregateScripts(opts *options.Options, td *parser.TemplateData, dg *parser.DepGraph, templateScriptsData *[]appshell.SlotItemData, templatesSeen *map[string][]appshell.SlotItemData) {
	if _, ok := (*templatesSeen)[td.MetaData.MetaDataPath]; ok {
		return
	}

	for _, path := range (*dg)[td.MetaData.MetaDataPath].LayoutPaths {
		if _, ok := (*templatesSeen)[path]; ok {
			continue
		}

		templateData := getTemplateData(opts, path)
		aggregateScriptDeps(opts, &templateData, dg, templateScriptsData, templatesSeen)
		appendInternalScripts(&templateData, templateScriptsData, parser.TemplateKind[parser.Layout])

		(*templatesSeen)[templateData.MetaData.MetaDataPath] = *templateScriptsData
	}

	aggregateScriptDeps(opts, td, dg, templateScriptsData, templatesSeen)
	appendInternalScripts(td, templateScriptsData, parser.TemplateKind[parser.Layout])

	(*templatesSeen)[td.MetaData.MetaDataPath] = *templateScriptsData
}

func appendInternalScripts(td *parser.TemplateData, templateScriptsData *[]appshell.SlotItemData, loc string) {
	item := appshell.SlotItemData{}
	item.Path = td.MetaData.MetaDataPath
	item.Typ = loc

	if len(item.Boundaries) == 0 {
		item.Boundaries = make([]string, 2)
	}

	// hash := "WF" + utils.ComputeHash(2, 4)

	// if len(hi.Attrs) == 0 {
	// 	(*hi).Attrs = map[string]string{}
	// } else {
	// 	for key := range (*hi).Attrs {
	// 		if key[:2] == "WF" {
	// 			hash = key
	// 		}
	// 	}
	// }

	idx := indexOf(*templateScriptsData, "Path", td.MetaData.MetaDataPath)

	// Handle first item
	if idx == -1 {
		// item.Boundaries[0] = "body " + hash
		// hi.Attrs[hash] = ""

		item.HTML.Open = utils.TruncateStringWhitespace(td.Script.Data)

		isWhiteSpace := true

		for _, ch := range item.HTML.Open {
			if !unicode.IsSpace(rune(ch)) {
				isWhiteSpace = false
			}
		}

		if isWhiteSpace {
			return
		}

		*templateScriptsData = append(*templateScriptsData, item)
		return
	}

	// // Generate hash attr for last item
	// if lastItem {
	// 	(*templateScriptsData)[idx].Boundaries[1] = "head " + hash
	// 	hi.Attrs[hash] = ""
	// }

	isWhiteSpace := true

	for _, ch := range (*templateScriptsData)[idx].HTML.Open {
		if !unicode.IsSpace(rune(ch)) {
			isWhiteSpace = false
		}
	}

	if isWhiteSpace {
		return
	}

	(*templateScriptsData)[idx].HTML.Open += utils.TruncateStringWhitespace(td.Script.Data)
}

func aggregateScriptDeps(opts *options.Options, td *parser.TemplateData, dg *parser.DepGraph, templateScriptData *[]appshell.SlotItemData, templatesSeen *map[string][]appshell.SlotItemData) {
	for _, dep := range (*dg)[td.MetaData.MetaDataPath].Deps {
		if dep.Kind.Value != "import" {
			continue
		}

		depth := ""
		for i := 0; i < td.MetaData.AdditionalDepth; i++ {
			depth += "../"
		}

		metaDataPath := filepath.Join(strings.Split(td.MetaData.MetaDataPath, filepath.Base(td.MetaData.MetaDataPath))[0], depth+strings.Split(dep.Path.RelPath, filepath.Ext(dep.Path.RelPath))[0]+".json")

		if _, ok := (*templatesSeen)[metaDataPath]; ok {
			continue
		}

		templateData := getTemplateData(opts, metaDataPath)

		appendInternalScripts(&templateData, templateScriptData, dep.Attrs["name"])
		aggregateScriptDeps(opts, &templateData, dg, templateScriptData, templatesSeen)

		(*templatesSeen)[metaDataPath] = *templateScriptData
	}
}

// var ran = false

// func compileScripts() {
// 	if ran == true {
// 		return
// 	}

// 	ran = true

// 	op1 := runIsolate("fetch('https://www.example.com').then(res => res.text())")
// 	fmt.Printf("%.25q...\n", op1)
// 	op2 := runIsolate("const multiply = (a, b) => a * b; multiply(2, 2)")
// 	fmt.Printf("%s\n", op2)
// }

// func runIsolate(script string) string {
// 	iso := v8go.NewIsolate()
// 	global := v8go.NewObjectTemplate(iso)

// 	if err := fetch.InjectTo(iso, global); err != nil {
// 		log.Fatal(err)
// 	}

// 	ctx := v8go.NewContext(iso, global)
// 	defer ctx.Close()

// 	if err := console.InjectTo(ctx); err != nil {
// 		log.Fatal(err)
// 	}

// 	output, e := ctx.RunScript(script, "function.js")
// 	if e != nil {
// 		log.Fatalf("Error: %+v\n", e)
// 	}

// 	if output.String() != "[object Promise]" {
// 		return output.String()
// 	}

// 	proms, err := output.AsPromise()
// 	if err != nil {
// 		panic(err)
// 	}
// 	done := make(chan bool, 1)

// 	go func() {
// 		for proms.State() == v8go.Pending {
// 			continue
// 		}
// 		done <- true
// 	}()

// 	select {
// 	case <-time.After(time.Second * 10):
// 		panic(errors.New("request timeout"))
// 	case <-done:
// 		html := proms.Result().String()
// 		return html
// 	}
// }
