// Copyright Martin Dosch.
// Use of this source code is governed by the BSD-2-clause
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"net"
	"os"
	"strings"

	"github.com/xmppo/go-xmpp"        // BSD-3-Clause
	"salsa.debian.org/mdosch/xmppsrv" // BSD-2-Clause
)

func connect(options xmpp.Options, directTLS bool, anon bool) (*xmpp.Client, error) {
	var server string
	proxy := os.Getenv("HTTP_PROXY")
	if !anon {
		server = options.User[strings.Index(options.User, "@")+1:]
	} else {
		server = options.User
	}
	// Look up SRV records or hostmeta2 if server is not specified manually
	// or if anon authentication is used.
	if options.Host == "" || anon {
		// Don't do SRV or hostmeta2 look ups if proxy is set.
		// TODO: 2024-10-30: Support hostmeta2 look ups using proxy.
		if proxy == "" {
			// Look up xmpp-client SRV records.
			srvMixed, err := xmppsrv.LookupClient(server)
			if len(srvMixed) > 0 && err == nil {
				for _, adr := range srvMixed {
					switch {
					case directTLS && adr.Type == "xmpp-client":
						continue
					case adr.Type == "xmpp-client":
						// Use StartTLS
						options.NoTLS = true
						options.StartTLS = true
					case adr.Type == "xmpps-client":
						// Use direct TLS
						options.NoTLS = false
						options.StartTLS = false
					default:
						continue
					}
					options.Host = net.JoinHostPort(adr.Target, fmt.Sprint(adr.Port))
					// Connect to server
					client, err := options.NewClient()
					if err == nil {
						return client, nil
					}
				}
			}
			// Look up hostmeta2 file.
			hm2, httpStatus, err := xmppsrv.LookupHostmeta2(server)
			if httpStatus != 404 && err != nil {
				for _, link := range hm2.Links {
					if link.Rel == nsC2SdTLS {
						options.NoTLS = false
						options.StartTLS = false
						options.Host = net.JoinHostPort(link.Sni, fmt.Sprint(link.Port))
						// Connect to server
						client, err := options.NewClient()
						if err == nil {
							return client, nil
						}
					}
				}
			}
		}
	}
	_, port, _ := net.SplitHostPort(options.Host)
	if port == "" {
		if options.Host == "" {
			options.Host = server
		}
		// Try port 5223 if directTLS is set and no port is provided.
		if directTLS {
			options.NoTLS = false
			options.StartTLS = false
			options.Host = net.JoinHostPort(options.Host, "5223")
		} else {
			// Try port 5222 if no port is provided and directTLS is not set.
			options.NoTLS = true
			options.StartTLS = true
			options.Host = net.JoinHostPort(options.Host, "5222")
		}
	}
	// Connect to server
	client, err := options.NewClient()
	if err == nil {
		return client, nil
	}
	return client, fmt.Errorf("connect: failed to connect to server: %w", err)
}
