package main

import (
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
)

type Proxy struct {
	targetURL *url.URL
	proxy     *httputil.ReverseProxy
}

// NewProxy 创建一个新的反向代理实例
func NewProxy(target string) (*Proxy, error) {
	parsedURL, err := url.Parse(target)
	if err != nil {
		return nil, fmt.Errorf("invalid target URL: %v", err)
	}
	return &Proxy{
		targetURL: parsedURL,
		proxy:     httputil.NewSingleHostReverseProxy(parsedURL),
	}, nil
}

// ServeHTTP 处理反向代理的请求
func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	// 日志记录请求信息
	log.Printf("Proxying request from %s: %s %s -> %s", r.RemoteAddr, r.Method, r.URL.Path, p.targetURL.String())

	// 自定义 Director 以调整请求
	p.proxy.Director = func(req *http.Request) {
		req.URL.Scheme = p.targetURL.Scheme
		req.URL.Host = p.targetURL.Host
		req.URL.Path = singleJoiningSlash(p.targetURL.Path, req.URL.Path)
		req.Header.Set("X-Forwarded-Host", req.Host)
		req.Header.Set("X-Origin-Host", p.targetURL.Host)
	}
	p.proxy.ServeHTTP(w, r)
}

// singleJoiningSlash 确保路径拼接时只有一个 "/"
func singleJoiningSlash(a, b string) string {
	aslash := strings.HasSuffix(a, "/")
	bslash := strings.HasPrefix(b, "/")
	switch {
	case aslash && bslash:
		return a + b[1:]
	case !aslash && !bslash:
		return a + "/" + b
	}
	return a + b
}

func main() {
	target := "http://127.0.0.1:20023"
	addr := "127.0.0.1:8081"

	proxy, err := NewProxy(target)
	if err != nil {
		log.Fatalf("Error creating proxy: %v", err)
	}

	fmt.Printf("Reverse proxy server listening on: %s, targeting: %s\n", addr, target)
	if err := http.ListenAndServe(addr, proxy); err != nil {
		log.Fatalf("Error starting server: %v", err)
	}
}