package javascript

import (
	"github.com/charmbracelet/log"
	"golang.org/x/net/html"
	"os"
	"path"
	"strings"

	"github.com/evanw/esbuild/pkg/api"
)

func ParseHTMLFile(p string, development bool) error {
	data, err := os.ReadFile(p)
	if err != nil {
		return err
	}

	doc, err := html.Parse(strings.NewReader(string(data)))
	if err != nil {
		return err
	}

	var f func(*html.Node)
	f = func(n *html.Node) {

		var src, source, scriptDist, styleDist, target string

		if n.Type == html.ElementNode && n.Data == "script" {
			for _, attr := range n.Attr {
				if attr.Key == "data-bob-source" {
					source = attr.Val
				} else if attr.Key == "data-bob-script-dist" {
					scriptDist = attr.Val
				} else if attr.Key == "data-bob-style-dist" {
					styleDist = attr.Val
				} else if attr.Key == "data-bob-target" {
					target = attr.Val
				} else if attr.Key == "src" {
					src = attr.Val
				}
			}

			if src != "" {

				if !path.IsAbs(source) {
					source = path.Dir(p) + "/" + source

					if _, err := os.Stat(source); os.IsNotExist(err) {
						log.Error("File does not exist: " + source)
						return
					}

				}

				if !path.IsAbs(scriptDist) {
					scriptDist = path.Dir(p) + "/" + scriptDist
				}

				if !path.IsAbs(styleDist) {
					styleDist = path.Dir(p) + "/" + styleDist
				}

				log.Info("Script: " + src + " " + source + " " + scriptDist + " " + styleDist)

				runESBuild(source, path.Dir(p), scriptDist, styleDist, development, target)

			}

		}
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			f(c)
		}
	}

	f(doc)

	return nil
}

func runESBuild(source, dist, scriptDist, styleDist string, development bool, target string) {

	// get temporary directory
	//tempDir, err := os.MkdirTemp("", "build-bob")
	//if err != nil {
	//	fmt.Println("Fehler beim Erstellen des temporären Verzeichnisses:", err)
	//	return
	//}
	//
	//defer func() {
	//	err := os.RemoveAll(tempDir)
	//	if err != nil {
	//		fmt.Println("Fehler beim Löschen des temporären Verzeichnisses:", err)
	//	}
	//
	//}()

	var treeShaking = api.TreeShakingTrue
	if development {
		treeShaking = api.TreeShakingFalse
	}

	keepNames := development
	esbuildTarget := api.ESNext
	if target != "" {
		switch {
		case target == "es5" || target == "es2015":
			esbuildTarget = api.ES5
			keepNames = false
		case target == "es6" || target == "es2016":
			esbuildTarget = api.ES2016
		case target == "es7" || target == "es2017":
			esbuildTarget = api.ES2017
		case target == "es8" || target == "es2018":
			esbuildTarget = api.ES2018
		case target == "es9" || target == "es2019":
			esbuildTarget = api.ES2019
		case target == "es10" || target == "es2020":
			esbuildTarget = api.ES2020
		case target == "es11" || target == "es2021":
			esbuildTarget = api.ES2021
		case target == "es12" || target == "es2022":
			esbuildTarget = api.ES2022
		case target == "es13" || target == "es2023":
			esbuildTarget = api.ES2023
		case target == "es14" || target == "es2024":
			esbuildTarget = api.ES2024
		default:
			log.Error("Unknown target: " + target + ". Using ESNext")

		}
	}

	footer := map[string]string{
		"js": `
/*
 * Copyright protects this code. Use, reproduction, or
 * modification of this code without prior written permission from the copyright holder
 * is strictly prohibited. For inquiries regarding licenses or usage rights,
 * please contact schukai GmbH.
 */`,
		"css": `
/*
 * Copyright protects this code. Use, reproduction, or
 * modification of this code without prior written permission from the copyright holder
 * is strictly prohibited. For inquiries regarding licenses or usage rights,
 * please contact schukai GmbH.
 */
`,
	}

	var sourceMap = api.SourceMapNone
	if development {
		sourceMap = api.SourceMapInline
	}

	result := api.Build(api.BuildOptions{
		EntryPoints: []string{source},
		Outfile:     path.Join(path.Base(scriptDist)),
		Bundle:      true,
		Write:       false,
		LogLevel:    api.LogLevelInfo,
		Target:      esbuildTarget,

		MinifySyntax:      !development,
		MinifyWhitespace:  !development,
		MinifyIdentifiers: !development,
		TreeShaking:       treeShaking,
		KeepNames:         keepNames,

		Sourcemap:     sourceMap,
		LegalComments: api.LegalCommentsExternal,

		Footer: footer,
	})

	if len(result.Errors) > 0 {
		for _, err := range result.Errors {
			log.Error(err.Text)
		}
	}

	for _, warning := range result.Warnings {
		log.Warn(warning.Text)
	}

	for _, file := range result.OutputFiles {
		switch path.Ext(file.Path) {
		case ".mjs":
			err := os.WriteFile(scriptDist, file.Contents, os.ModePerm)
			if err != nil {
				log.Error(err.Error())
			} else {
				log.Info("Saved " + scriptDist)
			}

		case ".js":
			err := os.WriteFile(scriptDist, file.Contents, os.ModePerm)
			if err != nil {
				log.Error(err.Error())
			} else {
				log.Info("Saved " + scriptDist)
			}

		case ".css":
			err := os.WriteFile(styleDist, file.Contents, os.ModePerm)
			if err != nil {
				log.Error(err.Error())
			} else {
				log.Info("Saved " + styleDist)
			}

		case ".txt":

			content := file.Contents
			if strings.TrimSpace(string(content)) == "" {
				continue
			}

			if strings.Contains(file.Path, "LEGAL") {

				if development {
					log.Info("Legal information not saved in development mode")
					continue
				}

				if strings.Contains(file.Path, "js") {
					out := path.Join(path.Dir(scriptDist), path.Base(file.Path))
					err := os.WriteFile(out, file.Contents, os.ModePerm)
					if err != nil {
						log.Error(err.Error())
					} else {
						log.Info("Saved " + out)
					}
				} else {
					out := path.Join(path.Dir(styleDist), path.Base(file.Path))
					err := os.WriteFile(out, file.Contents, os.ModePerm)
					if err != nil {
						log.Error(err.Error())
					} else {
						log.Info("Saved " + out)
					}
				}

			}

		}

	}

}