// Copyright (c) 2024 RethinkDNS and its authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package backend

const ( // see dnsx/transport.go
	// DNS transport types
	DOH      = "DNS-over-HTTPS"
	DNSCrypt = "DNSCrypt"
	DNS53    = "DNS"
	DOT      = "DNS-over-TLS"
	ODOH     = "Oblivious DNS-over-HTTPS"

	CT = "Cache" // cached transport prefix

	// special singleton DNS transports (IDs)

	// Multiple DoH, DoT, ODoH resolvers
	Plus = "Plus"
	// Go determined default resolver (built-in)
	Goos = "Goos"
	// network/os provided dns (init using intra.SetSystemDNS)
	System = "System"
	// mdns; never cached! (built-in)
	Local = "mdns"
	// default (fallback) dns, used in place of special transports when unavailable
	// (init using intra.AddDefaultTransport)
	Default = "Default"
	// client preferred dns
	Preferred = "Preferred"
	// synthesizes answers from presets (built-in)
	Preset = "Preset"
	// synthesizes A/AAAA from a single fixed IP (built-in)
	Fixed = "Fixed"
	// a transport that bypasses local blocklists (dnsx.SetRdnsLocal);
	// if not set, Default is used
	BlockFree = "BlockFree"
	// all queries are blocked, answers never cached (built-in)
	BlockAll = "BlockAll"
	// Bootstrap DNS (built-in); encapsulates Default, if set; or Goos, otherwise.
	Bootstrap = "Bootstrap"
	// Application-level gateway
	Alg = "Alg"
	// dnscrypt.Proxy as a DNS Transport
	DcProxy = "DcProxy"
	// dns resolver for dns resolvers and for firestack (built-in)
	// delegates queries to Bootstrap.
	IpMapper = "IpMapper"
)

const ( // from dnsx/queryerror.go
	// Start: Transaction started
	Start = iota
	// Complete : Transaction completed successfully
	Complete
	// SendFailed : Failed to send query
	SendFailed
	// NoResponse : Got no response
	NoResponse
	// BadQuery : Malformed input
	BadQuery
	// BadResponse : Response was invalid
	BadResponse
	// InternalError : This should never happen
	InternalError
	// TransportError: Transport has issues
	TransportError
	// ClientError: Client has issues
	ClientError
	// Paused: Transport is paused
	Paused
	// DEnd: Transport stopped
	DEnd
)

const ( // from: dnsx/rethinkdns.go
	EB32 = iota
	EB64
)

// DNSTransport exports necessary methods from dnsx.Transport
type DNSTransport interface {
	// uniquely identifies this transport
	ID() *Gostr
	// one of DNS53, DOH, DNSCrypt, System
	Type() *Gostr
	// Median round-trip time for this transport, in millis.
	P50() int64
	// Return the server host address used to initialize this transport.
	GetAddr() *Gostr
	// Return the proxy (relay) always used by this transport.
	// Returns nil if there isn't any.
	GetRelay() Proxy
	// State of the transport after previous query (see: queryerror.go)
	Status() int
}

type DNSTransportMult interface {
	DNSTransportProvider
	// Add adds a transport to this multi-transport.
	Add(t DNSTransport) bool
	// Remove removes a transport from this multi-transport.
	Remove(id *Gostr) bool
	// Refresh re-registers transports and returns a csv of active ones.
	Refresh() (*Gostr, error)
	// LiveTransports returns a csv of active transports.
	LiveTransports() *Gostr
}

type DNSTransportProvider interface {
	// Get returns a transport from this multi-transport.
	Get(id *Gostr) (DNSTransport, error)
}

type RDNS interface {
	// SetStamp sets the rethinkdns blockstamp.
	SetStamp(*Gostr) error
	// GetStamp returns the current rethinkdns blockstamp.
	GetStamp() (*Gostr, error)
	// StampToNames returns csv group:names of blocklists in the given stamp s.
	StampToNames(s *Gostr) (*Gostr, error)
	// FlagsToStamp returns a blockstamp for given csv blocklist-ids, if valid.
	FlagsToStamp(csv *Gostr, enctyp int) (*Gostr, error)
	// StampToFlags retruns csv blocklist-ids given a valid blockstamp s.
	StampToFlags(s *Gostr) (*Gostr, error)
}

type RDNSResolver interface {
	// SetRdnsLocal sets the local rdns resolver.
	SetRdnsLocal(trie, rank, conf, filetag string) error
	// GetRdnsLocal returns the local rdns resolver.
	GetRdnsLocal() (RDNS, error)
	// SetRdnsRemote sets the remote rdns resolver.
	SetRdnsRemote(filetag string) error
	// GetRdnsRemote returns the remote rdns resolver.
	GetRdnsRemote() (RDNS, error)
	// Translate enables or disables ALG/fixed responses
	Translate(bool)
}

type DNSTransportMultProvider interface {
	// GetMult returns a multi-transport by id.
	GetMult(id *Gostr) (DNSTransportMult, error)
}

type DNSResolver interface {
	DNSTransportMult
	DNSTransportMultProvider
	RDNSResolver
}

type ResolverListener interface {
	// OnDNSAdded is called when a new DNS transport with id is added.
	OnDNSAdded(id *Gostr)
	// OnDNSRemoved is called when a DNS transport with id is removed, except
	// when the transport is stopped, then OnDNSStopped is called instead.
	OnDNSRemoved(id *Gostr)
	// OnDNSStopped is called when all DNS transports are stopped. Note:
	// OnDNSRemoved is not called for each transport even if they are
	// being removed and not just stopped.
	OnDNSStopped()
}
