//go:build !windows
// +build !windows

package transparent

import (
	"context"
	"fmt"
	"net"
	"os/exec"
	"runtime"
	"strings"
	"syscall"

	"github.com/sirupsen/logrus"
)

type TransparentProxy struct {
	logger          *logrus.Logger
	proxyPort       int
	transparentPort int
	dnsPort         int
	originalDNS     []string
	rules           []string
}

type Config struct {
	ProxyPort       int      // HTTP代理端口
	TransparentPort int      // 透明代理端口
	DNSPort         int      // DNS代理端口
	BypassIPs       []string // 不代理的IP列表
	BypassDomains   []string // 不代理的域名列表
}

func NewTransparentProxy(config Config, logger *logrus.Logger) *TransparentProxy {
	if config.TransparentPort == 0 {
		config.TransparentPort = 8888
	}
	if config.DNSPort == 0 {
		config.DNSPort = 5353
	}

	return &TransparentProxy{
		logger:          logger,
		proxyPort:       config.ProxyPort,
		transparentPort: config.TransparentPort,
		dnsPort:         config.DNSPort,
		rules:           make([]string, 0),
	}
}

// SetupTransparentProxy 设置透明代理规则
func (tp *TransparentProxy) SetupTransparentProxy(ctx context.Context) error {
	if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
		return fmt.Errorf("transparent proxy only supported on Linux and macOS")
	}

	tp.logger.Info("Setting up transparent proxy rules...")

	// 备份当前DNS设置
	if err := tp.backupDNS(); err != nil {
		tp.logger.WithError(err).Warn("Failed to backup DNS settings")
	}

	switch runtime.GOOS {
	case "linux":
		return tp.setupLinuxRules()
	case "darwin":
		return tp.setupMacOSRules()
	default:
		return fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
	}
}

// CleanupTransparentProxy 清理透明代理规则
func (tp *TransparentProxy) CleanupTransparentProxy() error {
	tp.logger.Info("Cleaning up transparent proxy rules...")

	var errors []string

	// 恢复DNS设置
	if err := tp.restoreDNS(); err != nil {
		errors = append(errors, fmt.Sprintf("DNS restore: %v", err))
	}

	switch runtime.GOOS {
	case "linux":
		if err := tp.cleanupLinuxRules(); err != nil {
			errors = append(errors, fmt.Sprintf("Linux rules: %v", err))
		}
	case "darwin":
		if err := tp.cleanupMacOSRules(); err != nil {
			errors = append(errors, fmt.Sprintf("macOS rules: %v", err))
		}
	}

	if len(errors) > 0 {
		return fmt.Errorf("cleanup errors: %s", strings.Join(errors, "; "))
	}

	return nil
}

// setupLinuxRules 设置Linux iptables规则
func (tp *TransparentProxy) setupLinuxRules() error {
	rules := []string{
		// 创建新的链
		"iptables -t nat -N WORMHOLE_OUTPUT",
		"iptables -t nat -N WORMHOLE_PREROUTING",

		// 跳过本地流量
		fmt.Sprintf("iptables -t nat -A WORMHOLE_OUTPUT -d 127.0.0.0/8 -j RETURN"),
		fmt.Sprintf("iptables -t nat -A WORMHOLE_OUTPUT -d 10.0.0.0/8 -j RETURN"),
		fmt.Sprintf("iptables -t nat -A WORMHOLE_OUTPUT -d 172.16.0.0/12 -j RETURN"),
		fmt.Sprintf("iptables -t nat -A WORMHOLE_OUTPUT -d 192.168.0.0/16 -j RETURN"),

		// 重定向TCP流量到透明代理
		fmt.Sprintf("iptables -t nat -A WORMHOLE_OUTPUT -p tcp -j REDIRECT --to-ports %d", tp.transparentPort),

		// 应用规则
		"iptables -t nat -A OUTPUT -j WORMHOLE_OUTPUT",
		"iptables -t nat -A PREROUTING -j WORMHOLE_PREROUTING",

		// DNS重定向
		fmt.Sprintf("iptables -t nat -A WORMHOLE_PREROUTING -p udp --dport 53 -j REDIRECT --to-ports %d", tp.dnsPort),
		fmt.Sprintf("iptables -t nat -A WORMHOLE_OUTPUT -p udp --dport 53 -j REDIRECT --to-ports %d", tp.dnsPort),
	}

	return tp.executeRules(rules)
}

// setupMacOSRules 设置macOS pfctl规则
func (tp *TransparentProxy) setupMacOSRules() error {
	// macOS需要使用pfctl，配置更复杂
	pfRules := fmt.Sprintf(`
# Wormhole transparent proxy rules
rdr pass on lo0 inet proto tcp from any to any port 1:65535 -> 127.0.0.1 port %d
rdr pass on lo0 inet proto udp from any to any port 53 -> 127.0.0.1 port %d
pass out quick proto tcp from any to any flags S/SA keep state
pass out quick proto udp from any to any keep state
`, tp.transparentPort, tp.dnsPort)

	// 写入pfctl规则文件
	if err := tp.writePfRules(pfRules); err != nil {
		return err
	}

	// 加载规则
	rules := []string{
		"pfctl -f /tmp/wormhole.pf.conf",
		"pfctl -e",
	}

	return tp.executeRules(rules)
}

// GetOriginalDestination 获取透明代理的原始目标地址
func (tp *TransparentProxy) GetOriginalDestination(conn net.Conn) (string, error) {
	tcpConn, ok := conn.(*net.TCPConn)
	if !ok {
		return "", fmt.Errorf("not a TCP connection")
	}

	// 获取socket文件描述符
	file, err := tcpConn.File()
	if err != nil {
		return "", err
	}
	defer file.Close()

	fd := int(file.Fd())

	switch runtime.GOOS {
	case "linux":
		return tp.getLinuxOriginalDest(fd)
	case "darwin":
		return tp.getMacOSOriginalDest(fd)
	default:
		return "", fmt.Errorf("unsupported OS for transparent proxy")
	}
}

func (tp *TransparentProxy) executeRules(rules []string) error {
	for _, rule := range rules {
		tp.rules = append(tp.rules, rule)

		parts := strings.Fields(rule)
		if len(parts) == 0 {
			continue
		}

		cmd := exec.Command(parts[0], parts[1:]...)
		if output, err := cmd.CombinedOutput(); err != nil {
			tp.logger.WithFields(logrus.Fields{
				"rule":   rule,
				"output": string(output),
			}).WithError(err).Error("Failed to execute rule")
			// 继续执行其他规则，不要因为一个失败就停止
		} else {
			tp.logger.WithField("rule", rule).Debug("Rule executed successfully")
		}
	}
	return nil
}

func (tp *TransparentProxy) cleanupLinuxRules() error {
	cleanupRules := []string{
		"iptables -t nat -D OUTPUT -j WORMHOLE_OUTPUT",
		"iptables -t nat -D PREROUTING -j WORMHOLE_PREROUTING",
		"iptables -t nat -F WORMHOLE_OUTPUT",
		"iptables -t nat -F WORMHOLE_PREROUTING",
		"iptables -t nat -X WORMHOLE_OUTPUT",
		"iptables -t nat -X WORMHOLE_PREROUTING",
	}

	return tp.executeRules(cleanupRules)
}

func (tp *TransparentProxy) cleanupMacOSRules() error {
	rules := []string{
		"pfctl -d",
		"rm -f /tmp/wormhole.pf.conf",
	}

	return tp.executeRules(rules)
}

func (tp *TransparentProxy) backupDNS() error {
	// 这里简化处理，实际应该备份/etc/resolv.conf
	tp.originalDNS = []string{"8.8.8.8", "8.8.4.4"}
	return nil
}

func (tp *TransparentProxy) restoreDNS() error {
	// 恢复DNS设置
	tp.logger.Info("DNS settings restored")
	return nil
}

func (tp *TransparentProxy) writePfRules(rules string) error {
	return exec.Command("sh", "-c", fmt.Sprintf("echo '%s' > /tmp/wormhole.pf.conf", rules)).Run()
}

func (tp *TransparentProxy) getLinuxOriginalDest(fd int) (string, error) {
	// Linux SO_ORIGINAL_DST
	const SO_ORIGINAL_DST = 80

	_, err := syscall.GetsockoptIPv6Mreq(fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST)
	if err != nil {
		return "", err
	}

	// 解析地址结构（这里简化处理）
	return "unknown:80", nil
}

func (tp *TransparentProxy) getMacOSOriginalDest(fd int) (string, error) {
	// macOS implementation would be more complex
	return "unknown:80", nil
}

// IsTransparentSupported 检查系统是否支持透明代理
func IsTransparentSupported() bool {
	switch runtime.GOOS {
	case "linux":
		// 检查是否有iptables
		if _, err := exec.LookPath("iptables"); err != nil {
			return false
		}
		return true
	case "darwin":
		// 检查是否有pfctl
		if _, err := exec.LookPath("pfctl"); err != nil {
			return false
		}
		return true
	default:
		return false
	}
}

// RequiresRoot 检查是否需要root权限
func RequiresRoot() bool {
	return runtime.GOOS == "linux" || runtime.GOOS == "darwin"
}
