package clash

import (
	"fmt"
	"strings"

	"github.com/perfect-panel/server/pkg/adapter/proxy"
)

func parseShadowsocks(s proxy.Proxy, uuid string) (*Proxy, error) {
	config, ok := s.Option.(proxy.Shadowsocks)
	if !ok {
		return nil, fmt.Errorf("invalid type for Shadowsocks")
	}
	p := &Proxy{
		Name:     s.Name,
		Type:     "ss",
		Server:   s.Server,
		Port:     s.Port,
		Cipher:   config.Method,
		Password: uuid,
		UDP:      true,
	}

	if strings.Contains(p.Cipher, "2022") {
		serverKey, userKey := proxy.GenerateShadowsocks2022Password(config, uuid)
		p.Password = fmt.Sprintf("%s:%s", serverKey, userKey)
	}

	return p, nil
}

func parseTrojan(data proxy.Proxy, password string) (*Proxy, error) {
	trojan, ok := data.Option.(proxy.Trojan)
	if !ok {
		return nil, fmt.Errorf("invalid type for Trojan")
	}
	p := &Proxy{
		Name:           data.Name,
		Type:           "trojan",
		Server:         data.Server,
		Port:           data.Port,
		Password:       password,
		SNI:            trojan.SecurityConfig.SNI,
		SkipCertVerify: trojan.SecurityConfig.AllowInsecure,
	}
	setTransportOptions(p, trojan.Transport, trojan.TransportConfig)
	return p, nil
}

func parseVless(data proxy.Proxy, uuid string) (*Proxy, error) {
	vless, ok := data.Option.(proxy.Vless)
	if !ok {
		return nil, fmt.Errorf("invalid type for Vless")
	}
	p := &Proxy{
		Name:   data.Name,
		Type:   "vless",
		Server: data.Server,
		Port:   data.Port,
		UUID:   uuid,
		Flow:   vless.Flow,
		UDP:    true,
	}
	setSecurityOptions(p, vless.Security, vless.SecurityConfig)
	clashTransport(p, vless.Transport, vless.TransportConfig)
	return p, nil
}

func parseVmess(data proxy.Proxy, uuid string) (*Proxy, error) {
	vmess, ok := data.Option.(proxy.Vmess)
	if !ok {
		return nil, fmt.Errorf("invalid type for Vmess")
	}
	alterID := 0
	p := &Proxy{
		Name:    data.Name,
		Type:    "vmess",
		Server:  data.Server,
		Port:    data.Port,
		UUID:    uuid,
		AlterID: &alterID,
		Cipher:  "auto",
	}
	setSecurityOptions(p, vmess.Security, vmess.SecurityConfig)
	clashTransport(p, vmess.Transport, vmess.TransportConfig)
	return p, nil
}

func parseHysteria2(data proxy.Proxy, uuid string) (*Proxy, error) {
	hysteria2, ok := data.Option.(proxy.Hysteria2)
	if !ok {
		return nil, fmt.Errorf("invalid type for Hysteria2")
	}
	p := &Proxy{
		Name:              data.Name,
		Type:              "hysteria2",
		Server:            data.Server,
		Port:              data.Port,
		Ports:             hysteria2.HopPorts,
		Password:          uuid,
		HeartbeatInterval: hysteria2.HopInterval,
		SkipCertVerify:    hysteria2.SecurityConfig.AllowInsecure,
		SNI:               hysteria2.SecurityConfig.SNI,
	}
	if hysteria2.ObfsPassword != "" {
		p.Obfs = "salamander"
		p.ObfsPassword = hysteria2.ObfsPassword
	}

	return p, nil
}

func parseTuic(data proxy.Proxy, uuid string) (*Proxy, error) {
	tuic, ok := data.Option.(proxy.Tuic)
	if !ok {
		return nil, fmt.Errorf("invalid type for Tuic")
	}

	p := &Proxy{
		Name:                 data.Name,
		Type:                 "tuic",
		Server:               data.Server,
		Port:                 data.Port,
		UUID:                 uuid,
		Password:             uuid,
		ALPN:                 []string{"h3"},
		DisableSni:           tuic.DisableSNI,
		ReduceRtt:            tuic.ReduceRtt,
		CongestionController: tuic.CongestionController,
		UdpRelayMode:         tuic.UDPRelayMode,
		SNI:                  tuic.SecurityConfig.SNI,
		SkipCertVerify:       tuic.SecurityConfig.AllowInsecure,
	}

	return p, nil
}

func parseAnyTLS(data proxy.Proxy, uuid string) (*Proxy, error) {
	anyTLS, ok := data.Option.(proxy.AnyTLS)
	if !ok {
		return nil, fmt.Errorf("invalid type for AnyTLS")
	}

	p := &Proxy{
		Name:     data.Name,
		Type:     "anytls",
		Server:   data.Server,
		Port:     data.Port,
		Password: uuid,
		UDP:      true,
		ALPN: []string{
			"h2",
			"http/1.1",
		},
	}

	if anyTLS.SecurityConfig.SNI != "" {
		p.SNI = anyTLS.SecurityConfig.SNI
	}
	if anyTLS.SecurityConfig.AllowInsecure {
		p.SkipCertVerify = anyTLS.SecurityConfig.AllowInsecure
	}

	return p, nil
}

func setSecurityOptions(p *Proxy, security string, config proxy.SecurityConfig) {
	switch security {
	case "tls":
		p.TLS = true
		p.ServerName = config.SNI
		p.ClientFingerprint = config.Fingerprint
		p.SkipCertVerify = config.AllowInsecure
	case "reality":
		p.TLS = true
		p.ServerName = config.SNI
		p.ClientFingerprint = config.Fingerprint
		p.RealityOpts = RealityOptions{
			PublicKey: config.RealityPublicKey,
			ShortID:   config.RealityShortId,
		}
		p.SkipCertVerify = config.AllowInsecure
	default:
		p.TLS = false
	}
}

func setTransportOptions(p *Proxy, transport string, config proxy.TransportConfig) {
	switch transport {
	case "websocket":
		p.Network = "ws"
		p.WSOpts = WSOptions{
			Path: config.Path,
			Headers: map[string]string{
				"Host": config.Host,
			},
		}
	case "grpc":
		p.Network = "grpc"
		p.GrpcOpts = GrpcOptions{
			GrpcServiceName: config.ServiceName,
		}
	default:
		p.Network = "tcp"
	}
}
