package tunnel

import (
	"errors"
	"net/http"
	"net/http/httputil"
	"strings"
	"time"

	"github.com/engigu/baihu-panel/internal/logger"
	
	"github.com/gin-gonic/gin"
	"github.com/hashicorp/yamux"
)

// Copyright (c) 2026 engigu (Baihu Panel). All rights reserved.
// Use of this source code is governed by the Apache License 2.0.
// 
// 【重要声明 / IMPORTANT NOTICE】
// 本代码（包括其架构设计与核心实现）属于白虎面板（Baihu Panel）开源项目的一部分。
// 任何个人或组织在引用、移植、修改或重新分发此文件中的任何代码时，必须保留本版权声明，
// 并在您的衍生作品、文档、软件关于页面或说明文件中显式声明引用自白虎面板（Baihu Panel）。
// 
// Anyone referencing, porting, modifying, or redistributing this code must retain this 
// copyright notice and explicitly state the source: Baihu Panel (github.com/engigu/baihu-panel).

// ProxyHTTP 以完全透明的流式转发将 HTTP 请求代理到远程节点 (主节点调用)
func ProxyHTTP(nodeID string, c *gin.Context, targetPath string) error {
	sess := GetSession(nodeID)
	if sess == nil {
		return errors.New("node is offline or tunnel not established")
	}

	if sess.Token == "" {
		return errors.New("node token not found in session cache")
	}

	// 获取真实客户端 IP，传递给子节点用于审计日志等
	clientIP := c.ClientIP()

	director := func(req *http.Request) {
		req.URL.Scheme = "http"
		req.URL.Host = "tunnel.local"
		req.URL.Path = targetPath
		// gin 和 httputil 默认会保留并透传 Query 参数

		req.Header.Set("Authorization", "Bearer "+sess.Token)
		// 删除父节点的 Cookie 避免干扰子节点的会话验证
		req.Header.Del("Cookie")

		// 强制加上该 Header，防止出现节点相互代理的死循环
		req.Header.Set("X-Tunnel-Proxy", "true")
		
		// 传递真实的客户端 IP 给子节点
		if clientIP != "" {
			req.Header.Set("X-Forwarded-For", clientIP)
		}
	}

	proxy := &httputil.ReverseProxy{
		Director:  director,
		Transport: sess.Transport, // 直接复用 AddSession 时创建的全局连接池，由原生库处理 Context 取消
		ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
			logger.Errorf("[Tunnel] 节点 %s 代理隧道请求发生错误: %v", nodeID, err)
			w.WriteHeader(http.StatusBadGateway)
			w.Write([]byte("Tunnel connection error: " + err.Error()))
		},
	}

	proxy.ServeHTTP(c.Writer, c.Request)
	return nil
}

// serveLocalProxy 本地服务代理逻辑 (子节点调用)
func serveLocalProxy(session *yamux.Session) {
	if LocalEngine == nil {
		logger.Errorf("[Tunnel] 无法启动本地代理服务，因为 LocalEngine 尚未注入。")
		return
	}

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// 安全规则 1：防止互相调用的死循环
		if strings.HasPrefix(r.URL.Path, "/api/v1/interconnect/proxy/") {
			w.WriteHeader(http.StatusForbidden)
			w.Write([]byte("Recursive proxy loops are not allowed via tunnel"))
			return
		}

		// 安全规则已放宽：允许访问所有路径 (包括前端静态资源和 API)，以支持主从版本不一致时的完整穿透。
		// 由 LocalEngine (Gin) 自行决定哪些接口需要认证。

		// 确保保留 X-Tunnel-Proxy 请求头，以防后续逻辑需要判定
		r.Header.Set("X-Tunnel-Proxy", "true")

		// 纯内存函数调用，直接扔给 Gin 引擎，零网络开销！
		LocalEngine.ServeHTTP(w, r)
	})

	server := &http.Server{
		Handler:     handler,
		ReadTimeout: 15 * time.Second,
		IdleTimeout: 15 * time.Second,
	}

	// 监听会话关闭信号，主动关闭 http.Server 以彻底释放协程
	go func() {
		<-session.CloseChan()
		server.Close()
	}()

	// yamux.Session 实现了标准的 net.Listener 接口！
	err := server.Serve(session)
	if err != nil && err != http.ErrServerClosed && err != yamux.ErrSessionShutdown {
		logger.Errorf("[Tunnel] Yamux 代理服务意外停止: %v", err)
	}
}
