package assets

import (
	"net/url"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"openreplay/backend/pkg/flakeid"
)

func getSessionKey(sessionID uint64) string {
	return strconv.FormatUint(
		uint64(time.UnixMilli(
			int64(flakeid.ExtractTimestamp(sessionID)),
		).Day()),
		10,
	)
}

func ResolveURL(baseurl string, rawurl string) string {
	rawurl = strings.Trim(rawurl, " ")
	if !isRelativeCachable(rawurl) {
		return rawurl
	}
	baseurl = strings.Split(baseurl, "#")[0] // remove #fragment suffix if present
	base, _ := url.ParseRequestURI(baseurl)  // fn Only for base urls
	u, _ := url.Parse(rawurl)                // TODO: handle errors ?
	if base == nil || u == nil {
		return rawurl
	}
	return base.ResolveReference(u).String() // ResolveReference same as base.Parse(rawurl)
}

func isRelativeCachable(relativeURL string) bool {
	if len(relativeURL) == 0 || relativeURL[0] == '#' {
		return false
	}
	return true
}
func isCachable(rawurl string) bool {
	u, _ := url.Parse(rawurl)
	if u == nil || u.User != nil {
		return false
	}
	if u.Scheme != "http" && u.Scheme != "https" {
		return false
	}
	ext := filepath.Ext(u.Path)
	return ext == ".css" ||
		ext == ".ashx" || // ASP .NET
		ext == ".woff" ||
		ext == ".woff2" ||
		ext == ".ttf" ||
		ext == ".otf" ||
		ext == ".eot"
}

func GetFullCachableURL(baseURL string, relativeURL string) (string, bool) {
	if !isRelativeCachable(relativeURL) {
		return relativeURL, false
	}
	fullURL := ResolveURL(baseURL, relativeURL)
	if !isCachable(fullURL) {
		return fullURL, false
	}
	return fullURL, true
}

func getCachePath(rawurl string) string {
	return "/" + strings.ReplaceAll(url.QueryEscape(rawurl), "%", "!") // s3 keys are ok with "!"
}

func getCachePathWithKey(sessionID uint64, rawurl string) string {
	return getCachePath(rawurl) + "." + getSessionKey(sessionID) // Be carefull with slashes
}

func GetCachePathForJS(rawurl string) string {
	return getCachePath(rawurl)
}

func GetCachePathForAssets(sessionID uint64, rawurl string) string {
	return getCachePathWithKey(sessionID, rawurl)
}

func (r *Rewriter) RewriteURL(sessionID uint64, baseURL string, relativeURL string) string {
	fullURL, cachable := GetFullCachableURL(baseURL, relativeURL)
	if !cachable {
		return fullURL
	}

	u := url.URL{
		Path:   r.assetsURL.Path + getCachePathWithKey(sessionID, fullURL),
		Host:   r.assetsURL.Host,
		Scheme: r.assetsURL.Scheme,
	}
	return u.String()
}
