package service

import (
	"net/url"
	"slices"
	"strings"
)

// Headers holds request header key/value pairs.
type Headers = map[string]string

// Heuristic represents a heuristic for detecting a remote service type, e.g. WebDAV.
type Heuristic struct {
	Type    Type
	Domains []string
	Paths   []string
	Method  string
	Headers Headers
}

// Heuristics for common remote service types.
var Heuristics = []Heuristic{
	{Type: Facebook, Domains: []string{"facebook.com", "www.facebook.com"}, Paths: []string{}, Method: "GET"},
	{Type: Twitter, Domains: []string{"twitter.com"}, Paths: []string{}, Method: "GET"},
	{Type: Flickr, Domains: []string{"flickr.com", "www.flickr.com"}, Paths: []string{}, Method: "GET"},
	{Type: Instagram, Domains: []string{"instagram.com", "www.instagram.com"}, Paths: []string{}, Method: "GET"},
	{Type: Telegram, Domains: []string{"web.telegram.org", "www.telegram.org", "telegram.org"}, Paths: []string{}, Method: "GET"},
	{Type: WhatsApp, Domains: []string{"web.whatsapp.com", "www.whatsapp.com", "whatsapp.com"}, Paths: []string{}, Method: "GET"},
	{Type: OneDrive, Domains: []string{"onedrive.live.com"}, Paths: []string{}, Method: "GET"},
	{Type: GDrive, Domains: []string{"drive.google.com"}, Paths: []string{}, Method: "GET"},
	{Type: GPhotos, Domains: []string{"photos.google.com"}, Paths: []string{}, Method: "GET"},
	{Type: WebDAV,
		Domains: []string{},
		Paths:   []string{"/", "/webdav/", "/originals/", "/import/", "/remote.php/dav/files/{user}/", "/remote.php/webdav/", "/dav/files/{user}/", "/servlet/webdav.infostore/"},
		Method:  "PROPFIND",
		Headers: Headers{"Depth": "1"},
	},
}

// MatchDomain returns true if the heuristic allows the provided domain.
func (h Heuristic) MatchDomain(match string) bool {
	if len(h.Domains) == 0 {
		return true
	}

	return slices.Contains(h.Domains, match)
}

// Discover returns the first matching endpoint URL for the heuristic.
func (h Heuristic) Discover(rawUrl, user string) *url.URL {
	u, err := url.Parse(rawUrl)

	if err != nil {
		return nil
	}

	if h.TestRequest(h.Method, u.String()) {
		return u
	}

	for _, p := range h.Paths {
		u.Path = strings.ReplaceAll(p, "{user}", user)

		if h.TestRequest(h.Method, u.String()) {
			return u
		}
	}

	return nil
}
