package helper

import (
	"context"
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"

	"golang.org/x/net/proxy"
)

/*
创建代理

  - @proxyType 代理类别 http\https\socks5
  - @proxyAddr 代理地址 userName:password@endpoint:port
*/
func CreateHtppProxy(proxyType, proxyAddr string, client *http.Client) error {
	// Set up proxy based on type (HTTP, HTTPS, SOCKS5)
	transport := &http.Transport{
		TLSHandshakeTimeout: 10 * time.Second,
	}
	if proxyAddr != "" {
		if !strings.HasPrefix(proxyAddr, "http://") && !strings.HasPrefix(proxyAddr, "https://") && !strings.HasPrefix(proxyAddr, "socks5://") {
			proxyAddr = proxyType + "://" + proxyAddr
		}

		if proxyType == "" {
			proxyType = strings.Split(proxyAddr, "://")[0]
		}

		switch proxyType {
		case "http", "https":
			proxyURL, err := url.Parse(proxyAddr)
			if err != nil {
				return errors.New(fmt.Sprintf("invalid proxy URL: %w", err))
			}
			// Check if proxy URL contains credentials
			if proxyURL.User != nil {
				username := proxyURL.User.Username()
				password, _ := proxyURL.User.Password()
				transport.Proxy = func(req *http.Request) (*url.URL, error) {
					req.SetBasicAuth(username, password) // Set basic auth headers
					return proxyURL, nil
				}
			} else {
				transport.Proxy = http.ProxyURL(proxyURL)
			}
		case "socks5":
			proxyURL, err := url.Parse(proxyAddr)
			if err != nil {
				return errors.New(fmt.Sprintf("invalid proxy URL: %w", err))
			}

			var auth *proxy.Auth
			if proxyURL.User != nil {
				auth = &proxy.Auth{
					User:     proxyURL.User.Username(),
					Password: getProxyPassword(proxyURL),
				}
			}

			dialer, err := proxy.SOCKS5("tcp", proxyURL.Host, auth, proxy.Direct)
			if err != nil {
				return errors.New(fmt.Sprintf("failed to set up SOCKS5 proxy: %w", err))
			}
			transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
				return dialer.Dial(network, addr)
			}
		default:
			return errors.New(fmt.Sprintf("unsupported proxy type: %s", proxyType))
		}

		client.Transport = transport
	}

	return nil
}
