package main

import (
	"bytes"
	"io"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strconv"
	"strings"
	"time"
)

func main() {
	// Production Configuration
	basePath := "/hemanta/external_proxy"
	masterHost := "gw1dev.atguru.work"
	targetURLStr := "http://gwheman2.apextsi.com"
	listenAddr := ":7070"

	// Standard logging defaults to stderr/stdout, which is perfect for systemd/docker
	log.Printf("=== Production Reverse Proxy Starting ===")
	log.Printf("Base Path: %s", basePath)
	log.Printf("Target: %s", targetURLStr)
	log.Printf("Time: %s", time.Now().Format(time.RFC3339))

	targetURL, err := url.Parse(targetURLStr)
	if err != nil {
		log.Fatalf("CRITICAL: Invalid target URL: %v", err)
	}

	proxy := httputil.NewSingleHostReverseProxy(targetURL)

	// Modify outgoing requests
	origDirector := proxy.Director
	proxy.Director = func(req *http.Request) {
		// Strip base path before fetching
		strippedPath := strings.TrimPrefix(req.URL.Path, basePath)
		if strippedPath == "" {
			strippedPath = "/"
		}

		origDirector(req)
		req.URL.Scheme = targetURL.Scheme
		req.URL.Host = targetURL.Host
		req.URL.Path = strippedPath
		req.Host = targetURL.Host
	}

	// Modify responses
	proxy.ModifyResponse = func(resp *http.Response) error {
		upPrefix := targetURL.Scheme + "://" + targetURL.Host
		masterPrefix := "https://" + masterHost

		// 1. Fix Location header (redirects)
		if loc := resp.Header.Get("Location"); loc != "" {
			newLoc := loc
			if strings.HasPrefix(loc, upPrefix) {
				newLoc = strings.Replace(loc, upPrefix, masterPrefix+basePath, 1)
			} else if strings.HasPrefix(loc, "/") {
				newLoc = basePath + loc
			}
			if newLoc != loc {
				resp.Header.Set("Location", newLoc)
			}
		}

		// 2. Fix cookies
		cookies := resp.Header.Values("Set-Cookie")
		if len(cookies) > 0 {
			resp.Header.Del("Set-Cookie")
			for _, c := range cookies {
				c = strings.ReplaceAll(c, "Domain="+targetURL.Host, "Domain="+masterHost)
				c = strings.ReplaceAll(c, "Domain=."+targetURL.Host, "Domain="+masterHost)

				if !strings.Contains(c, "Path=") {
					c = c + "; Path=" + basePath + "/"
				} else {
					c = strings.ReplaceAll(c, "Path=/", "Path="+basePath+"/")
				}

				if !strings.Contains(c, "Secure") {
					c = c + "; Secure"
				}
				resp.Header.Add("Set-Cookie", c)
			}
		}

		// 3. Rewrite HTML/CSS/JS
		ct := resp.Header.Get("Content-Type")
		if strings.Contains(ct, "text/html") ||
			strings.Contains(ct, "text/css") ||
			strings.Contains(ct, "javascript") ||
			strings.Contains(ct, "application/json") {

			body, err := io.ReadAll(resp.Body)
			if err != nil {
				// ERROR LOG ADDED: Critical for debugging partial responses
				log.Printf("ERROR: Failed reading response body [Path: %s]: %v", resp.Request.URL.Path, err)
				return err
			}
			resp.Body.Close()

			bodyStr := string(body)

			// Replace absolute URLs
			bodyStr = strings.ReplaceAll(bodyStr, upPrefix+"/", masterPrefix+basePath+"/")
			bodyStr = strings.ReplaceAll(bodyStr, "//"+targetURL.Host+"/", "//"+masterHost+basePath+"/")

			// Replace relative URLs in attributes
			bodyStr = strings.ReplaceAll(bodyStr, `href="/`, `href="`+basePath+`/`)
			bodyStr = strings.ReplaceAll(bodyStr, `src="/`, `src="`+basePath+`/`)
			bodyStr = strings.ReplaceAll(bodyStr, `action="/`, `action="`+basePath+`/`)
			bodyStr = strings.ReplaceAll(bodyStr, `data-url="/`, `data-url="`+basePath+`/`)

			// CSS urls
			bodyStr = strings.ReplaceAll(bodyStr, `url(/`, `url(`+basePath+`/`)
			bodyStr = strings.ReplaceAll(bodyStr, `url("/`, `url("`+basePath+`/`)
			bodyStr = strings.ReplaceAll(bodyStr, `url('/`, `url('`+basePath+`/`)

			resp.Body = io.NopCloser(bytes.NewBufferString(bodyStr))
			resp.ContentLength = int64(len(bodyStr))
			resp.Header.Set("Content-Length", strconv.Itoa(len(bodyStr)))
		}

		return nil
	}

	proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
		// RemoteAddr to track who is triggering errors
		log.Printf("ERROR: Backend unreachable [Client: %s] [Method: %s] [Path: %s] -> %v", 
			r.RemoteAddr, r.Method, r.URL.Path, err)
		http.Error(w, "Proxy Error: Unable to reach backend", http.StatusBadGateway)
	}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		proxy.ServeHTTP(w, r)
	})

	log.Printf("System ready. Listening on %s", listenAddr)
	if err := http.ListenAndServe(listenAddr, nil); err != nil {
		log.Fatalf("CRITICAL: Server failed to start: %v", err)
	}
}
