package main

import (
	"crypto/tls"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"regexp"
	"strings"
	"time"
)

const (
	listenAddr     = "127.0.0.1:6060"
	upstreamScheme = "https"               // LAN server forces HTTPS
	upstreamHost   = "dev1.private.com"        // direct LAN IP
	publicHost     = "ssl1.atguru.work"
	publicScheme   = "https"
	pathPrefix     = "/hemanta/LBer_LAN"
)

var (
	domainAttrRe = regexp.MustCompile(`(?i);?\s*Domain=[^;]+`)
	pathAttrRe   = regexp.MustCompile(`(?i)Path=([^;]+)`)
)

func main() {
	upstreamURL := &url.URL{
		Scheme: upstreamScheme,
		Host:   upstreamHost,
	}

	// Minimal startup log only
	log.Printf("[START] Reverse proxy on %s → %s://%s %s",
		listenAddr, upstreamScheme, upstreamHost, pathPrefix)

	server := &http.Server{
		Addr:         listenAddr,
		Handler:      newReverseProxy(upstreamURL),
		ReadTimeout:  30 * time.Second,
		WriteTimeout: 60 * time.Second,
		IdleTimeout:  90 * time.Second,
	}

	// Only log fatal errors
	if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
		log.Fatalf("[FATAL] Server failed: %v", err)
	}
}

func newReverseProxy(target *url.URL) *httputil.ReverseProxy {
	director := func(req *http.Request) {

		// Strip prefix for upstream
		if strings.HasPrefix(req.URL.Path, pathPrefix) {
			p := strings.TrimPrefix(req.URL.Path, pathPrefix)
			if p == "" {
				p = "/"
			}
			if !strings.HasPrefix(p, "/") {
				p = "/" + p
			}
			req.URL.Path = p
		}

		req.URL.Scheme = target.Scheme
		req.URL.Host = target.Host

		// Send original Host for backend compatibility
		req.Host = "dev1.private.com"
		req.Header.Set("Host", "dev1.private.com")

		// Forward important headers
		if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
			req.Header.Set("X-Real-IP", clientIP)
			if prior := req.Header.Get("X-Forwarded-For"); prior != "" {
				req.Header.Set("X-Forwarded-For", prior+", "+clientIP)
			} else {
				req.Header.Set("X-Forwarded-For", clientIP)
			}
		}
		req.Header.Set("X-Forwarded-Host", publicHost)
		req.Header.Set("X-Forwarded-Proto", "https")
	}

	modifyResp := func(resp *http.Response) error {

		// Rewrite Location headers
		if loc := resp.Header.Get("Location"); loc != "" {
			resp.Header.Set("Location", rewriteLocation(loc))
		}

		// Rewrite Set-Cookie for domain/path
		if cookies := resp.Header["Set-Cookie"]; len(cookies) > 0 {
			newCookies := make([]string, 0, len(cookies))
			for _, c := range cookies {
				c2 := domainAttrRe.ReplaceAllString(c, "")
				if m := pathAttrRe.FindStringSubmatch(c2); len(m) == 2 {
					orig := m[1]
					newPath := strings.TrimRight(pathPrefix, "/") + "/" + strings.TrimLeft(orig, "/")
					c2 = pathAttrRe.ReplaceAllString(c2, "Path="+newPath)
				} else {
					c2 = strings.TrimSuffix(c2, ";") + "; Path=" + pathPrefix + "/"
				}
				newCookies = append(newCookies, strings.TrimSpace(c2))
			}
			resp.Header["Set-Cookie"] = newCookies
		}

		return nil
	}

	rp := &httputil.ReverseProxy{
		Director:       director,
		ModifyResponse: modifyResp,

		// Minimal error logging only
		ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
			log.Printf("[ERROR] Upstream error: %v", err)
			http.Error(w, "Upstream error", http.StatusBadGateway)
		},

		FlushInterval: 100 * time.Millisecond,
	}

	// HTTPS transport (LAN)
	rp.Transport = &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}

	return rp
}

func rewriteLocation(loc string) string {
	loc = strings.TrimSpace(loc)

	// Absolute redirect from upstream
	if strings.HasPrefix(loc, "http://") || strings.HasPrefix(loc, "https://") {
		u, err := url.Parse(loc)
		if err == nil {
			if u.Host == "dev1.private.com" || u.Host == upstreamHost {
				newPath := strings.TrimRight(pathPrefix, "/") + "/" + strings.TrimLeft(u.Path, "/")
				out := publicScheme + "://" + publicHost + newPath
				if u.RawQuery != "" {
					out += "?" + u.RawQuery
				}
				return out
			}
			return loc
		}
	}

	// Relative redirects
	if strings.HasPrefix(loc, "/") {
		newPath := strings.TrimRight(pathPrefix, "/") + "/" + strings.TrimLeft(loc, "/")
		return publicScheme + "://" + publicHost + newPath
	}

	return loc
}
