package filter

import (
	"crypto/tls"
	"net"
	"time"
	"strconv"
	
	"find-me-internet/internal/model"
)

// Pipeline represents the filter configuration
type Pipeline struct {
	Timeout time.Duration
}

func NewPipeline(timeout time.Duration) *Pipeline {
	return &Pipeline{Timeout: timeout}
}

// Check performs the TCP & TLS checks
// Returns true if the proxy is worth testing with Sing-box
func (f *Pipeline) Check(p *model.Proxy) bool {
	// 1. Syntax Check
	if p.Address == "" || p.Port == 0 || p.Type == model.TypeUnknown {
		return false
	}

	// 2. TCP Connect (Liveness)
	if !f.checkTCP(p) {
		p.IsOnline = false
		return false // Dead
	}
	p.IsOnline = true

	// 3. TLS Handshake (Validity)
	// Only run this if the proxy uses TLS (SNI is present or it's a TLS protocol)
	// For VLESS/Trojan, TLS is standard. For VMess, it's optional.
	if p.SNI != "" || p.Port == 443 {
		if !f.checkTLS(p) {
			p.IsTLSSecure = false
			// If it expects TLS but fails handshake, it's likely a firewall block or dead cert
			return false 
		}
		p.IsTLSSecure = true
	}

	return true
}

// checkTCP attempts a raw socket connection
func (f *Pipeline) checkTCP(p *model.Proxy) bool {
	address := net.JoinHostPort(p.Address, strconv.Itoa(p.Port))
	conn, err := net.DialTimeout("tcp", address, f.Timeout)
	if err != nil {
		return false
	}
	conn.Close()
	return true
}

// checkTLS attempts a TLS handshake
func (f *Pipeline) checkTLS(p *model.Proxy) bool {
	address := net.JoinHostPort(p.Address, strconv.Itoa(p.Port))
	
	dialer := &net.Dialer{Timeout: f.Timeout}
	
	// We use InsecureSkipVerify because many proxies use self-signed certs or Reality.
	// We only care that the server *speaks* TLS and accepts our SNI.
	conf := &tls.Config{
		InsecureSkipVerify: true,
		ServerName:         p.SNI, 
	}
	
	// If no SNI is parsed, try the host address (common for direct connections)
	if conf.ServerName == "" {
		conf.ServerName = p.Address
	}

	conn, err := tls.DialWithDialer(dialer, "tcp", address, conf)
	if err != nil {
		return false
	}
	conn.Close()
	return true
}