package urlutil

import (
	"os"
	"strings"

	errorutil "github.com/projectdiscovery/utils/errors"
)

const (
	HTTP  = "http"
	HTTPS = "https"

	// Deny all protocols
	// Allow:
	// websocket + websocket over ssl
	WEBSOCKET     = "ws"
	WEBSOCKET_SSL = "wss"
	FTP           = "ftp"

	SchemeSeparator  = "://"
	DefaultHTTPPort  = "80"
	DefaultHTTPSPort = "443"
)

// AutoMergeRelPaths merges two relative paths including parameters and returns final string
func AutoMergeRelPaths(path1 string, path2 string) (string, error) {
	if path1 == "" || path2 == "" {
		// no need to parse
		return mergePaths(path1, path2), nil
	}
	u1, err1 := ParseRelativePath(path1, true)
	if err1 != nil {
		return "", err1
	}
	u2, err2 := ParseRelativePath(path2, true)
	if err2 != nil {
		return "", err2
	}
	u1.Params.Merge(u2.Params.Encode())
	err := u1.MergePath(u2.Path, false)
	return u1.GetRelativePath(), err
}

// mergePaths merges two relative paths
func mergePaths(elem1 string, elem2 string) string {
	// if both have slash remove one
	if strings.HasSuffix(elem1, "/") && strings.HasPrefix(elem2, "/") {
		elem2 = strings.TrimLeft(elem2, "/")
	}

	if elem1 == "" {
		return elem2
	} else if elem2 == "" {
		return elem1
	}

	// if both paths donot have a slash add it to beginning of second
	if !strings.HasSuffix(elem1, "/") && !strings.HasPrefix(elem2, "/") {
		elem2 = "/" + elem2
	}

	// Do not normalize but combibe paths same as path.join
	// Merge Examples (Same as path.Join)
	// /blog   /admin => /blog/admin
	// /blog/wp /wp-content  => /blog/wp/wp-content
	// /blog/admin /blog/admin/profile => /blog/admin/profile
	// /blog/admin /blog => /blog/admin/blog
	// /blog /blog/ => /blog/

	if elem1 == elem2 {
		return elem1
	} else if len(elem1) > len(elem2) && strings.HasSuffix(elem1, elem2) {
		return elem1
	} else if len(elem1) < len(elem2) && strings.HasPrefix(elem2, elem1) {
		return elem2
	} else {
		return elem1 + elem2
	}
}

// ShouldEscapes returns true if given payload contains any characters
// that are not accepted by url or must be escaped
// this does not include seperators
func shouldEscape(ss string) bool {
	rmap := getrunemap(RFCEscapeCharSet)
	for _, v := range ss {
		switch {
		case v == '/':
			continue
		case v > rune(127):
			return true
		default:
			if _, ok := rmap[v]; ok {
				return true
			}
		}
	}
	return false
}

func init() {
	if os.Getenv("DEBUG") != "" {
		errorutil.ShowStackTrace = true
	}
}
