// Package tor implements Tor Hidden Service transport
package tor

import (
	"fmt"
	"net"
	"net/url"

	"golang.org/x/net/proxy"

	"khimera/transport"
)

// TorTransport implements Tor-based networking
type TorTransport struct {
	socksProxy string // SOCKS5 proxy address (default: 127.0.0.1:9050)
	dialer     proxy.Dialer
	listener   net.Listener
	closed     bool
}

// NewTorTransport creates a new Tor transport
func NewTorTransport(socksProxy string) (*TorTransport, error) {
	if socksProxy == "" {
		socksProxy = "127.0.0.1:9050" // Default Tor SOCKS proxy
	}

	// Create SOCKS5 dialer
	proxyURL, err := url.Parse("socks5://" + socksProxy)
	if err != nil {
		return nil, fmt.Errorf("invalid SOCKS proxy address: %w", err)
	}

	dialer, err := proxy.FromURL(proxyURL, proxy.Direct)
	if err != nil {
		return nil, fmt.Errorf("failed to create SOCKS dialer: %w", err)
	}

	return &TorTransport{
		socksProxy: socksProxy,
		dialer:     dialer,
	}, nil
}

// Connect connects to a Tor Hidden Service (.onion address)
func (t *TorTransport) Connect(address string) (net.Conn, error) {
	if t.closed {
		return nil, fmt.Errorf("tor transport is closed")
	}

	// Validate .onion address
	if !isOnionAddress(address) {
		return nil, fmt.Errorf("invalid .onion address: %s", address)
	}

	// Connect via SOCKS proxy
	conn, err := t.dialer.Dial("tcp", address)
	if err != nil {
		return nil, fmt.Errorf("failed to connect to %s: %w", address, err)
	}

	return conn, nil
}

// Listen starts a Tor Hidden Service listener
// Note: This is a simplified implementation. In production, you'd need to:
// 1. Configure torrc to create a hidden service
// 2. Get the .onion address from Tor control port
// 3. Listen on the local port specified in torrc
func (t *TorTransport) Listen(address string) (net.Listener, error) {
	if t.closed {
		return nil, fmt.Errorf("tor transport is closed")
	}

	if t.listener != nil {
		return nil, fmt.Errorf("already listening")
	}

	// Listen on localhost (Tor will forward to this)
	// In production, parse the address to get the port
	listener, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		return nil, fmt.Errorf("failed to create listener: %w", err)
	}

	t.listener = listener
	return listener, nil
}

// Type returns the transport type
func (t *TorTransport) Type() transport.TransportType {
	return transport.TransportTor
}

// Close closes the Tor transport
func (t *TorTransport) Close() error {
	if t.closed {
		return nil
	}

	t.closed = true

	if t.listener != nil {
		if err := t.listener.Close(); err != nil {
			return fmt.Errorf("failed to close listener: %w", err)
		}
		t.listener = nil
	}

	return nil
}

// GetSOCKSProxy returns the SOCKS proxy address
func (t *TorTransport) GetSOCKSProxy() string {
	return t.socksProxy
}

// isOnionAddress checks if an address is a valid .onion address
func isOnionAddress(address string) bool {
	// Simple validation: check if it contains ".onion"
	// In production, use regex to validate v3 onion addresses (56 chars base32)
	return len(address) > 6 && address[len(address)-6:] == ".onion" ||
	       len(address) > 13 && address[len(address)-13:len(address)-7] == ".onion:"
}

// String returns a string representation
func (t *TorTransport) String() string {
	return fmt.Sprintf("TorTransport(proxy=%s, closed=%v)", t.socksProxy, t.closed)
}
