package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/gotunnel/internal/server/app"
	"github.com/gotunnel/internal/server/config"
	"github.com/gotunnel/internal/server/db"
	"github.com/gotunnel/internal/server/tunnel"
	"github.com/gotunnel/pkg/crypto"
	"github.com/gotunnel/pkg/plugin"
	"github.com/gotunnel/pkg/plugin/builtin"
	"github.com/gotunnel/pkg/plugin/sign"
)

func main() {
	configPath := flag.String("c", "server.yaml", "config file path")
	flag.Parse()

	// 加载 YAML 配置
	cfg, err := config.LoadServerConfig(*configPath)
	if err != nil {
		log.Fatalf("Load config error: %v", err)
	}

	// 初始化数据库
	clientStore, err := db.NewSQLiteStore(cfg.Server.DBPath)
	if err != nil {
		log.Fatalf("Init database error: %v", err)
	}
	defer clientStore.Close()

	// 打印 token（便于客户端连接）
	log.Printf("[Server] Token: %s", cfg.Server.Token)

	// 创建隧道服务
	server := tunnel.NewServer(
		clientStore,
		cfg.Server.BindAddr,
		cfg.Server.BindPort,
		cfg.Server.Token,
		cfg.Server.HeartbeatSec,
		cfg.Server.HeartbeatTimeout,
	)

	// 配置 TLS（默认启用）
	if !cfg.Server.TLSDisabled {
		tlsConfig, err := crypto.GenerateTLSConfig()
		if err != nil {
			log.Fatalf("Generate TLS config error: %v", err)
		}
		server.SetTLSConfig(tlsConfig)
		log.Printf("[Server] TLS enabled")
	}

	// 初始化安全配置（撤销列表和公钥列表）
	initSecurityConfig()

	// 初始化插件系统
	registry := plugin.NewRegistry()
	if err := registry.RegisterAllServer(builtin.GetServerPlugins()); err != nil {
		log.Fatalf("[Plugin] Register error: %v", err)
	}
	server.SetPluginRegistry(registry)
	log.Printf("[Plugin] Registered %d plugins", len(builtin.GetServerPlugins()))

	// 加载 JS 插件配置
	if len(cfg.JSPlugins) > 0 {
		jsPlugins := loadJSPlugins(cfg.JSPlugins)
		server.LoadJSPlugins(jsPlugins)
	}

	// 启动 Web 控制台
	if cfg.Web.Enabled {
		// 强制生成 Web 凭据（如果未配置）
		if config.GenerateWebCredentials(cfg) {
			log.Printf("[Web] Auto-generated credentials - Username: %s, Password: %s",
				cfg.Web.Username, cfg.Web.Password)
			log.Printf("[Web] Please save these credentials and update your config file")
			// 保存配置以持久化凭据
			if err := config.SaveServerConfig(*configPath, cfg); err != nil {
				log.Printf("[Web] Warning: failed to save config: %v", err)
			}
		}

		ws := app.NewWebServer(clientStore, server, cfg, *configPath, clientStore)
		addr := fmt.Sprintf("%s:%d", cfg.Web.BindAddr, cfg.Web.BindPort)

		go func() {
			// 始终使用 JWT 认证
			err := ws.RunWithJWT(addr, cfg.Web.Username, cfg.Web.Password, cfg.Server.Token)
			if err != nil {
				log.Printf("[Web] Server error: %v", err)
			}
		}()
		log.Printf("[Web] Console running at http://%s (authentication required)", addr)
	}

	// 优雅关闭信号处理
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		<-quit
		log.Printf("[Server] Received shutdown signal")
		server.Shutdown(30 * time.Second)
		os.Exit(0)
	}()

	log.Fatal(server.Run())
}

// loadJSPlugins 加载 JS 插件文件
func loadJSPlugins(configs []config.JSPluginConfig) []tunnel.JSPluginEntry {
	var plugins []tunnel.JSPluginEntry

	for _, cfg := range configs {
		source, err := os.ReadFile(cfg.Path)
		if err != nil {
			log.Printf("[JSPlugin] Failed to load %s: %v", cfg.Path, err)
			continue
		}

		// 加载签名文件
		sigPath := cfg.SigPath
		if sigPath == "" {
			sigPath = cfg.Path + ".sig"
		}
		signature, err := os.ReadFile(sigPath)
		if err != nil {
			log.Printf("[JSPlugin] Failed to load signature for %s: %v", cfg.Name, err)
			continue
		}

		// 服务端也验证签名，防止配置文件被篡改
		if err := verifyPluginSignature(cfg.Name, string(source), string(signature)); err != nil {
			log.Printf("[JSPlugin] Signature verification failed for %s: %v", cfg.Name, err)
			continue
		}

		plugins = append(plugins, tunnel.JSPluginEntry{
			Name:      cfg.Name,
			Source:    string(source),
			Signature: string(signature),
			AutoPush:  cfg.AutoPush,
			Config:    cfg.Config,
			AutoStart: cfg.AutoStart,
		})

		log.Printf("[JSPlugin] Loaded: %s from %s (verified)", cfg.Name, cfg.Path)
	}

	return plugins
}

// verifyPluginSignature 验证插件签名
func verifyPluginSignature(name, source, signature string) error {
	// 解码签名
	signed, err := sign.DecodeSignedPlugin(signature)
	if err != nil {
		return fmt.Errorf("decode signature: %w", err)
	}

	// 检查插件是否被撤销
	if revoked, reason := sign.IsPluginRevoked(name, signed.Payload.Version); revoked {
		return fmt.Errorf("plugin revoked: %s", reason)
	}

	// 检查密钥是否已吊销
	if sign.IsKeyRevoked(signed.Payload.KeyID) {
		return fmt.Errorf("signing key revoked: %s", signed.Payload.KeyID)
	}

	// 获取公钥
	pubKey, err := sign.GetPublicKeyByID(signed.Payload.KeyID)
	if err != nil {
		return err
	}

	// 验证插件名称
	if signed.Payload.Name != name {
		return fmt.Errorf("name mismatch: %s vs %s", signed.Payload.Name, name)
	}

	// 验证签名
	return sign.VerifyPlugin(pubKey, signed, source)
}

// initSecurityConfig 初始化安全配置
func initSecurityConfig() {
	// 配置撤销列表
	sign.SetRevocationConfig(sign.RevocationConfig{
		RemoteURL:       config.OfficialRevocationURL,
		FetchInterval:   1 * time.Hour,
		RequestTimeout:  10 * time.Second,
		VerifySignature: true,
	})

	// 配置公钥列表
	sign.SetKeyListConfig(sign.KeyListConfig{
		RemoteURL:      config.OfficialKeyListURL,
		FetchInterval:  24 * time.Hour,
		RequestTimeout: 10 * time.Second,
	})

	// 启动后台刷新
	stopCh := make(chan struct{})
	go sign.StartRevocationRefresher(stopCh)

	// 立即拉取一次公钥列表
	if err := sign.FetchRemoteKeyList(); err != nil {
		log.Printf("[Security] Fetch key list failed: %v", err)
	}

	log.Printf("[Security] Initialized with remote revocation and key list")
}
