package main

import (
	"bufio"
	"context"
	"crypto/rsa"
	"crypto/x509"
	"database/sql"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	sf "github.com/snowflakedb/gosnowflake"
)

// =============================================================================
// VERSION & CONSTANTS
// =============================================================================

const (
	VERSION        = "1.0.0"
	APP_NAME       = "MetaMuLate Unified Proxy"
	CONFIG_FILE    = "proxy-config.json"
	DEFAULT_CORS_PORT      = 8080
	DEFAULT_SNOWFLAKE_PORT = 8081
)

// Log levels
const (
	LOG_SILENT  = 0
	LOG_ERROR   = 1
	LOG_WARN    = 2
	LOG_INFO    = 3
	LOG_DEBUG   = 4
	LOG_VERBOSE = 5
)

// =============================================================================
// CONFIGURATION
// =============================================================================

// ProxyConfig holds all configuration for both proxies
type ProxyConfig struct {
	// General settings
	LogLevel    int    `json:"log_level"`
	LogLevelStr string `json:"log_level_name"`

	// CORS Proxy settings
	CORSEnabled bool `json:"cors_enabled"`
	CORSPort    int  `json:"cors_port"`

	// Snowflake Proxy settings
	SnowflakeEnabled bool   `json:"snowflake_enabled"`
	SnowflakePort    int    `json:"snowflake_port"`
	SnowflakeAccount string `json:"snowflake_account,omitempty"`
	SnowflakeHost    string `json:"snowflake_host,omitempty"`
	SnowflakeUser    string `json:"snowflake_user,omitempty"`
	SnowflakePassword string `json:"snowflake_password,omitempty"`
	SnowflakeDatabase string `json:"snowflake_database,omitempty"`
	SnowflakeSchema   string `json:"snowflake_schema,omitempty"`
	SnowflakeWarehouse string `json:"snowflake_warehouse,omitempty"`
	SnowflakeRole     string `json:"snowflake_role,omitempty"`
	SnowflakePrivateKeyPath string `json:"snowflake_private_key_path,omitempty"`
	SnowflakeOAuthToken string `json:"snowflake_oauth_token,omitempty"`
	SnowflakeExternalBrowser bool `json:"snowflake_external_browser,omitempty"`
	
	// Timeouts
	QueryTimeout int `json:"query_timeout"`
	LoginTimeout int `json:"login_timeout"`
	ExternalBrowserTimeout int `json:"external_browser_timeout,omitempty"`
}

// =============================================================================
// LOGGING
// =============================================================================

var currentLogLevel = LOG_INFO

func logMessage(level int, prefix string, format string, args ...interface{}) {
	if level > currentLogLevel {
		return
	}
	
	timestamp := time.Now().Format("15:04:05")
	message := fmt.Sprintf(format, args...)
	fmt.Printf("[%s] %s %s\n", timestamp, prefix, message)
}

func logError(format string, args ...interface{}) {
	logMessage(LOG_ERROR, "❌", format, args...)
}

func logWarn(format string, args ...interface{}) {
	logMessage(LOG_WARN, "⚠️ ", format, args...)
}

func logInfo(format string, args ...interface{}) {
	logMessage(LOG_INFO, "ℹ️ ", format, args...)
}

func logSuccess(format string, args ...interface{}) {
	logMessage(LOG_INFO, "✅", format, args...)
}

func logDebug(format string, args ...interface{}) {
	logMessage(LOG_DEBUG, "🔍", format, args...)
}

func logVerbose(format string, args ...interface{}) {
	logMessage(LOG_VERBOSE, "📝", format, args...)
}

func logProxy(direction string, format string, args ...interface{}) {
	logMessage(LOG_INFO, direction, format, args...)
}

// =============================================================================
// INTERACTIVE CLI
// =============================================================================

var reader = bufio.NewReader(os.Stdin)

func prompt(question string) string {
	fmt.Print(question)
	answer, _ := reader.ReadString('\n')
	return strings.TrimSpace(answer)
}

func promptWithDefault(question string, defaultVal string) string {
	if defaultVal != "" {
		fmt.Printf("%s [%s]: ", question, defaultVal)
	} else {
		fmt.Printf("%s: ", question)
	}
	answer, _ := reader.ReadString('\n')
	answer = strings.TrimSpace(answer)
	if answer == "" {
		return defaultVal
	}
	return answer
}

func promptYesNo(question string, defaultYes bool) bool {
	defaultStr := "Y/n"
	if !defaultYes {
		defaultStr = "y/N"
	}
	fmt.Printf("%s [%s]: ", question, defaultStr)
	answer, _ := reader.ReadString('\n')
	answer = strings.TrimSpace(strings.ToLower(answer))
	
	if answer == "" {
		return defaultYes
	}
	return answer == "y" || answer == "yes"
}

func promptInt(question string, defaultVal int) int {
	fmt.Printf("%s [%d]: ", question, defaultVal)
	answer, _ := reader.ReadString('\n')
	answer = strings.TrimSpace(answer)
	if answer == "" {
		return defaultVal
	}
	val, err := strconv.Atoi(answer)
	if err != nil {
		return defaultVal
	}
	return val
}

func promptPassword(question string) string {
	fmt.Printf("%s: ", question)
	answer, _ := reader.ReadString('\n')
	return strings.TrimSpace(answer)
}

func promptSelect(question string, options []string, defaultIdx int) int {
	fmt.Println(question)
	for i, opt := range options {
		marker := "  "
		if i == defaultIdx {
			marker = "→ "
		}
		fmt.Printf("%s%d. %s\n", marker, i+1, opt)
	}
	fmt.Printf("Enter choice [%d]: ", defaultIdx+1)
	answer, _ := reader.ReadString('\n')
	answer = strings.TrimSpace(answer)
	if answer == "" {
		return defaultIdx
	}
	val, err := strconv.Atoi(answer)
	if err != nil || val < 1 || val > len(options) {
		return defaultIdx
	}
	return val - 1
}

// =============================================================================
// CONFIGURATION MANAGEMENT
// =============================================================================

func loadConfig(filename string) (*ProxyConfig, error) {
	data, err := os.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	
	config := &ProxyConfig{}
	if err := json.Unmarshal(data, config); err != nil {
		return nil, err
	}
	
	return config, nil
}

func saveConfig(config *ProxyConfig, filename string) error {
	data, err := json.MarshalIndent(config, "", "  ")
	if err != nil {
		return err
	}
	return os.WriteFile(filename, data, 0600)
}

func configExists(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil
}

func createNewConfig() *ProxyConfig {
	fmt.Println("")
	fmt.Println("═══════════════════════════════════════════════════════════════")
	fmt.Println("  🔧 MetaMuLate Proxy Configuration Wizard")
	fmt.Println("═══════════════════════════════════════════════════════════════")
	fmt.Println("")
	fmt.Println("No configuration file found. Let's create one!")
	fmt.Println("")
	
	config := &ProxyConfig{
		CORSPort:      DEFAULT_CORS_PORT,
		SnowflakePort: DEFAULT_SNOWFLAKE_PORT,
		QueryTimeout:  60,
		LoginTimeout:  30,
		ExternalBrowserTimeout: 120,
	}
	
	// Log level
	fmt.Println("━━━ Logging Settings ━━━")
	logLevels := []string{
		"Silent (no output)",
		"Errors only",
		"Errors + Warnings",
		"Info (recommended)",
		"Debug",
		"Verbose (everything)",
	}
	config.LogLevel = promptSelect("Select logging level:", logLevels, 3)
	config.LogLevelStr = logLevels[config.LogLevel]
	fmt.Println("")
	
	// CORS Proxy
	fmt.Println("━━━ CORS Proxy Settings ━━━")
	fmt.Println("The CORS proxy allows browser requests to APIs that don't support CORS.")
	fmt.Println("Used for: Discogs, Genius, and other third-party APIs.")
	config.CORSEnabled = promptYesNo("Enable CORS proxy?", true)
	if config.CORSEnabled {
		config.CORSPort = promptInt("CORS proxy port", DEFAULT_CORS_PORT)
	}
	fmt.Println("")
	
	// Snowflake Proxy
	fmt.Println("━━━ Snowflake Proxy Settings ━━━")
	fmt.Println("The Snowflake proxy enables secure database queries from the browser.")
	config.SnowflakeEnabled = promptYesNo("Enable Snowflake proxy?", false)
	
	if config.SnowflakeEnabled {
		config.SnowflakePort = promptInt("Snowflake proxy port", DEFAULT_SNOWFLAKE_PORT)
		fmt.Println("")
		fmt.Println("Enter your Snowflake connection details:")
		config.SnowflakeAccount = promptWithDefault("Account identifier (e.g., abc12345.us-east-1)", "")
		config.SnowflakeHost = promptWithDefault("Host (leave blank to auto-derive from account)", "")
		config.SnowflakeUser = promptWithDefault("Username", "")
		
		// Ask about authentication method
		authMethods := []string{
			"External Browser (SSO - recommended for interactive use)",
			"Password",
			"Private Key (JWT)",
		}
		authChoice := promptSelect("Select authentication method:", authMethods, 0)
		
		switch authChoice {
		case 0:
			config.SnowflakeExternalBrowser = true
			config.ExternalBrowserTimeout = promptInt("External browser timeout (seconds)", 120)
		case 1:
			config.SnowflakePassword = promptPassword("Password")
		case 2:
			config.SnowflakePrivateKeyPath = promptWithDefault("Private key path", "")
		}
		
		config.SnowflakeDatabase = promptWithDefault("Database", "")
		config.SnowflakeSchema = promptWithDefault("Schema", "PUBLIC")
		config.SnowflakeWarehouse = promptWithDefault("Warehouse", "COMPUTE_WH")
		config.SnowflakeRole = promptWithDefault("Role", "")
	}
	fmt.Println("")
	
	// Save config
	if promptYesNo("Save this configuration to "+CONFIG_FILE+"?", true) {
		if err := saveConfig(config, CONFIG_FILE); err != nil {
			logError("Failed to save config: %v", err)
		} else {
			logSuccess("Configuration saved to %s", CONFIG_FILE)
		}
	}
	
	return config
}

func askSessionSettings(config *ProxyConfig) *ProxyConfig {
	fmt.Println("")
	fmt.Println("═══════════════════════════════════════════════════════════════")
	fmt.Println("  🚀 Session Configuration")
	fmt.Println("═══════════════════════════════════════════════════════════════")
	fmt.Println("")
	
	// Create a copy for this session
	sessionConfig := *config
	
	// Ask which proxies to enable this session
	if config.CORSEnabled {
		sessionConfig.CORSEnabled = promptYesNo(fmt.Sprintf("Enable CORS proxy (port %d)?", config.CORSPort), true)
	}
	
	if config.SnowflakeEnabled && config.SnowflakeAccount != "" {
		sessionConfig.SnowflakeEnabled = promptYesNo(fmt.Sprintf("Enable Snowflake proxy (port %d)?", config.SnowflakePort), true)
	}
	
	// Log level for this session
	logLevels := []string{"Silent", "Errors", "Warnings", "Info", "Debug", "Verbose"}
	currentLevel := config.LogLevel
	if currentLevel < 0 || currentLevel >= len(logLevels) {
		currentLevel = 3
	}
	
	changeLogLevel := promptYesNo(fmt.Sprintf("Current log level: %s. Change it?", logLevels[currentLevel]), false)
	if changeLogLevel {
		sessionConfig.LogLevel = promptSelect("Select logging level:", logLevels, currentLevel)
	}
	
	currentLogLevel = sessionConfig.LogLevel
	
	fmt.Println("")
	return &sessionConfig
}

// =============================================================================
// CORS PROXY
// =============================================================================

var corsHeaders = map[string]string{
	"Access-Control-Allow-Origin":      "*",
	"Access-Control-Allow-Methods":     "GET, POST, PUT, DELETE, OPTIONS, PATCH",
	"Access-Control-Allow-Headers":     "*",
	"Access-Control-Expose-Headers":    "*",
	"Access-Control-Allow-Credentials": "true",
}

var corsHTTPClient = &http.Client{
	Timeout: 30 * time.Second,
}

func setCORSHeaders(w http.ResponseWriter) {
	for key, value := range corsHeaders {
		w.Header().Set(key, value)
	}
}

func handleCORSProxy(w http.ResponseWriter, r *http.Request) {
	setCORSHeaders(w)

	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	targetURL := r.URL.Query().Get("url")
	if targetURL == "" {
		targetURL = strings.TrimPrefix(r.URL.Path, "/")
	}

	if targetURL == "" {
		http.Error(w, "Missing 'url' parameter. Usage: http://localhost:PORT/?url=TARGET_URL", http.StatusBadRequest)
		return
	}

	logProxy("→", "CORS: %s %s", r.Method, targetURL)

	proxyReq, err := http.NewRequest(r.Method, targetURL, r.Body)
	if err != nil {
		logError("CORS: Failed to create request: %v", err)
		http.Error(w, fmt.Sprintf("Failed to create proxy request: %v", err), http.StatusInternalServerError)
		return
	}

	for key, values := range r.Header {
		if key == "Host" || key == "Origin" || key == "Referer" {
			continue
		}
		for _, value := range values {
			proxyReq.Header.Add(key, value)
		}
	}

	resp, err := corsHTTPClient.Do(proxyReq)
	if err != nil {
		logError("CORS: Proxy request failed: %v", err)
		http.Error(w, fmt.Sprintf("Proxy request failed: %v", err), http.StatusBadGateway)
		return
	}
	defer resp.Body.Close()

	logProxy("←", "CORS: %d %s", resp.StatusCode, resp.Status)

	for key, values := range resp.Header {
		for _, value := range values {
			w.Header().Add(key, value)
		}
	}

	setCORSHeaders(w)
	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
}

func startCORSProxy(port int, wg *sync.WaitGroup, shutdown chan struct{}) {
	defer wg.Done()
	
	mux := http.NewServeMux()
	mux.HandleFunc("/", handleCORSProxy)
	
	server := &http.Server{
		Addr:    fmt.Sprintf(":%d", port),
		Handler: mux,
	}
	
	go func() {
		<-shutdown
		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancel()
		server.Shutdown(ctx)
	}()
	
	logSuccess("CORS Proxy started on http://localhost:%d", port)
	logInfo("  Usage: http://localhost:%d/?url=TARGET_URL", port)
	
	if err := server.ListenAndServe(); err != http.ErrServerClosed {
		logError("CORS Proxy error: %v", err)
	}
}

// =============================================================================
// SNOWFLAKE PROXY
// =============================================================================

type SnowflakeProxy struct {
	config *ProxyConfig
	db     *sql.DB
	mu     sync.RWMutex
}

func NewSnowflakeProxy(config *ProxyConfig) *SnowflakeProxy {
	return &SnowflakeProxy{config: config}
}

func (sp *SnowflakeProxy) Connect() error {
	sp.mu.Lock()
	defer sp.mu.Unlock()
	
	// Build the host (required for credential caching)
	// Use configured host, or derive from account name
	host := sp.config.SnowflakeHost
	if host == "" {
		host = sp.config.SnowflakeAccount + ".snowflakecomputing.com"
	}
	
	cfg := &sf.Config{
		Account:   sp.config.SnowflakeAccount,
		Host:      host,
		User:      sp.config.SnowflakeUser,
		Database:  sp.config.SnowflakeDatabase,
		Schema:    sp.config.SnowflakeSchema,
		Warehouse: sp.config.SnowflakeWarehouse,
		Role:      sp.config.SnowflakeRole,
	}
	
	// Determine authentication method
	if sp.config.SnowflakeExternalBrowser {
		cfg.Authenticator = sf.AuthTypeExternalBrowser
		// Enable credential caching to avoid repeated browser auth
		// This stores the ID token in ~/.cache/snowflake/credential_cache_v1.json
		cfg.ClientStoreTemporaryCredential = sf.ConfigBoolTrue
		// Set external browser timeout
		if sp.config.ExternalBrowserTimeout > 0 {
			cfg.ExternalBrowserTimeout = time.Duration(sp.config.ExternalBrowserTimeout) * time.Second
		} else {
			cfg.ExternalBrowserTimeout = 120 * time.Second
		}
		logInfo("Using external browser (SSO) authentication with token caching enabled")
		logInfo("A browser window will open for authentication...")
	} else if sp.config.SnowflakePrivateKeyPath != "" {
		privateKey, err := loadPrivateKey(sp.config.SnowflakePrivateKeyPath)
		if err != nil {
			return fmt.Errorf("failed to load private key: %w", err)
		}
		cfg.Authenticator = sf.AuthTypeJwt
		cfg.PrivateKey = privateKey
		logDebug("Using JWT key-pair authentication")
	} else if sp.config.SnowflakeOAuthToken != "" {
		cfg.Authenticator = sf.AuthTypeOAuth
		cfg.Token = sp.config.SnowflakeOAuthToken
		logDebug("Using OAuth authentication")
	} else if sp.config.SnowflakePassword != "" {
		cfg.Password = sp.config.SnowflakePassword
		logDebug("Using password authentication")
	} else {
		return fmt.Errorf("no authentication method configured")
	}
	
	dsn, err := sf.DSN(cfg)
	if err != nil {
		return fmt.Errorf("failed to create DSN: %w", err)
	}
	
	db, err := sql.Open("snowflake", dsn)
	if err != nil {
		return fmt.Errorf("failed to open connection: %w", err)
	}
	
	// Test connection
	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(sp.config.LoginTimeout)*time.Second)
	defer cancel()
	
	if err := db.PingContext(ctx); err != nil {
		db.Close()
		return fmt.Errorf("failed to connect: %w", err)
	}
	
	sp.db = db
	logSuccess("Connected to Snowflake: %s", sp.config.SnowflakeAccount)
	return nil
}

func (sp *SnowflakeProxy) Close() {
	sp.mu.Lock()
	defer sp.mu.Unlock()
	if sp.db != nil {
		sp.db.Close()
		sp.db = nil
	}
}

func (sp *SnowflakeProxy) handleQuery(w http.ResponseWriter, r *http.Request) {
	setCORSHeaders(w)
	
	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}
	
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}
	
	var req struct {
		Query   string `json:"query"`
		Timeout int    `json:"timeout"`
	}
	
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}
	
	logProxy("→", "Snowflake: %s", truncateQuery(req.Query))
	
	timeout := req.Timeout
	if timeout <= 0 {
		timeout = sp.config.QueryTimeout
	}
	
	ctx, cancel := context.WithTimeout(r.Context(), time.Duration(timeout)*time.Second)
	defer cancel()
	
	sp.mu.RLock()
	db := sp.db
	sp.mu.RUnlock()
	
	if db == nil {
		http.Error(w, "Not connected to Snowflake", http.StatusServiceUnavailable)
		return
	}
	
	rows, err := db.QueryContext(ctx, req.Query)
	if err != nil {
		logError("Snowflake query failed: %v", err)
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusInternalServerError)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"success": false,
			"error":   err.Error(),
		})
		return
	}
	defer rows.Close()
	
	columns, _ := rows.Columns()
	var results [][]interface{}
	
	for rows.Next() {
		values := make([]interface{}, len(columns))
		valuePtrs := make([]interface{}, len(columns))
		for i := range values {
			valuePtrs[i] = &values[i]
		}
		
		if err := rows.Scan(valuePtrs...); err != nil {
			continue
		}
		
		// Convert values to JSON-safe types
		for i, v := range values {
			switch val := v.(type) {
			case []byte:
				values[i] = string(val)
			case time.Time:
				values[i] = val.Format(time.RFC3339)
			}
		}
		results = append(results, values)
	}
	
	logProxy("←", "Snowflake: %d rows", len(results))
	
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]interface{}{
		"success":  true,
		"columns":  columns,
		"data":     results,
		"rowCount": len(results),
	})
}

func (sp *SnowflakeProxy) handleHealth(w http.ResponseWriter, r *http.Request) {
	setCORSHeaders(w)
	
	sp.mu.RLock()
	db := sp.db
	sp.mu.RUnlock()
	
	response := map[string]interface{}{
		"service": "snowflake-proxy",
		"version": VERSION,
	}
	
	if db == nil {
		response["status"] = "disconnected"
	} else {
		ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
		defer cancel()
		
		if err := db.PingContext(ctx); err != nil {
			response["status"] = "error"
			response["error"] = err.Error()
		} else {
			response["status"] = "connected"
			response["account"] = sp.config.SnowflakeAccount
			response["database"] = sp.config.SnowflakeDatabase
		}
	}
	
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}

func (sp *SnowflakeProxy) handleRoot(w http.ResponseWriter, r *http.Request) {
	setCORSHeaders(w)
	w.Header().Set("Content-Type", "text/html")
	fmt.Fprintf(w, `<!DOCTYPE html>
<html>
<head><title>MetaMuLate Snowflake Proxy</title></head>
<body style="font-family: system-ui; padding: 2rem;">
<h1>❄️ MetaMuLate Snowflake Proxy</h1>
<p>Version: %s</p>
<h2>Endpoints:</h2>
<ul>
<li><code>GET /health</code> - Connection status</li>
<li><code>POST /query</code> - Execute SQL query</li>
</ul>
<h2>Query Example:</h2>
<pre>
POST /query
Content-Type: application/json

{
  "query": "SELECT * FROM table LIMIT 10",
  "timeout": 60
}
</pre>
</body>
</html>`, VERSION)
}

func startSnowflakeProxy(config *ProxyConfig, wg *sync.WaitGroup, shutdown chan struct{}) {
	defer wg.Done()
	
	proxy := NewSnowflakeProxy(config)
	
	if err := proxy.Connect(); err != nil {
		logError("Snowflake connection failed: %v", err)
		logWarn("Snowflake proxy will not be available")
		return
	}
	defer proxy.Close()
	
	mux := http.NewServeMux()
	mux.HandleFunc("/", proxy.handleRoot)
	mux.HandleFunc("/health", proxy.handleHealth)
	mux.HandleFunc("/query", proxy.handleQuery)
	
	server := &http.Server{
		Addr:    fmt.Sprintf(":%d", config.SnowflakePort),
		Handler: mux,
	}
	
	go func() {
		<-shutdown
		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancel()
		server.Shutdown(ctx)
	}()
	
	logSuccess("Snowflake Proxy started on http://localhost:%d", config.SnowflakePort)
	logInfo("  Endpoints: /health, /query")
	
	if err := server.ListenAndServe(); err != http.ErrServerClosed {
		logError("Snowflake Proxy error: %v", err)
	}
}

// =============================================================================
// HELPER FUNCTIONS
// =============================================================================

func loadPrivateKey(path string) (*rsa.PrivateKey, error) {
	keyData, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("failed to read key file: %w", err)
	}
	
	block, _ := pem.Decode(keyData)
	if block == nil {
		return nil, fmt.Errorf("failed to decode PEM block")
	}
	
	// Try PKCS#8 first
	key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err == nil {
		if rsaKey, ok := key.(*rsa.PrivateKey); ok {
			return rsaKey, nil
		}
		return nil, fmt.Errorf("not an RSA private key")
	}
	
	// Try PKCS#1
	rsaKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return nil, fmt.Errorf("failed to parse private key: %w", err)
	}
	
	return rsaKey, nil
}

func truncateQuery(query string) string {
	query = strings.ReplaceAll(query, "\n", " ")
	query = strings.Join(strings.Fields(query), " ")
	if len(query) > 80 {
		return query[:77] + "..."
	}
	return query
}

// =============================================================================
// MAIN
// =============================================================================

func printBanner() {
	fmt.Println("")
	fmt.Println("╔══════════════════════════════════════════════════════════════╗")
	fmt.Println("║                                                              ║")
	fmt.Println("║   🎵  MetaMuLate Unified Proxy  v" + VERSION + "                      ║")
	fmt.Println("║                                                              ║")
	fmt.Println("║   CORS Proxy + Snowflake Proxy in one application            ║")
	fmt.Println("║                                                              ║")
	fmt.Println("╚══════════════════════════════════════════════════════════════╝")
	fmt.Println("")
}

func printStatus(config *ProxyConfig) {
	fmt.Println("")
	fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
	fmt.Println("  Active Services")
	fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
	
	if config.CORSEnabled {
		fmt.Printf("  ✅ CORS Proxy:      http://localhost:%d\n", config.CORSPort)
	} else {
		fmt.Println("  ❌ CORS Proxy:      Disabled")
	}
	
	if config.SnowflakeEnabled {
		fmt.Printf("  ✅ Snowflake Proxy: http://localhost:%d\n", config.SnowflakePort)
	} else {
		fmt.Println("  ❌ Snowflake Proxy: Disabled")
	}
	
	logLevels := []string{"Silent", "Errors", "Warnings", "Info", "Debug", "Verbose"}
	level := config.LogLevel
	if level < 0 || level >= len(logLevels) {
		level = 3
	}
	fmt.Printf("  📊 Log Level:       %s\n", logLevels[level])
	
	fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
	fmt.Println("")
	fmt.Println("  Press Ctrl+C to stop all services")
	fmt.Println("")
}

func main() {
	// Check for --auto flag (skip interactive prompts) and --config flag
	autoMode := false
	configFile := CONFIG_FILE
	args := os.Args[1:]
	for i := 0; i < len(args); i++ {
		arg := args[i]
		if arg == "--auto" || arg == "-a" || arg == "--no-prompt" {
			autoMode = true
		}
		if (arg == "--config" || arg == "-c") && i+1 < len(args) {
			configFile = args[i+1]
			i++ // skip the next argument since we consumed it
		}
	}
	
	printBanner()
	
	var config *ProxyConfig
	
	// Check for existing config
	if configExists(configFile) {
		logInfo("Found configuration file: %s", configFile)
		
		var err error
		config, err = loadConfig(configFile)
		if err != nil {
			logError("Failed to load config: %v", err)
			logInfo("Creating new configuration...")
			config = createNewConfig()
		} else if !autoMode {
			// Ask for session settings only if not in auto mode
			config = askSessionSettings(config)
		} else {
			logInfo("Auto mode: using configuration as-is")
		}
	} else {
		// No config file - run setup wizard
		config = createNewConfig()
		
		// After creating config, ask session settings (unless auto mode)
		if !autoMode {
			config = askSessionSettings(config)
		}
	}
	
	// Set log level
	currentLogLevel = config.LogLevel
	
	// Check if anything is enabled
	if !config.CORSEnabled && !config.SnowflakeEnabled {
		logWarn("No services enabled. Enable at least one proxy to continue.")
		fmt.Println("")
		os.Exit(0)
	}
	
	// Print status
	printStatus(config)
	
	// Setup shutdown handling
	shutdown := make(chan struct{})
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
	
	var wg sync.WaitGroup
	
	// Start enabled services
	if config.CORSEnabled {
		wg.Add(1)
		go startCORSProxy(config.CORSPort, &wg, shutdown)
	}
	
	if config.SnowflakeEnabled {
		wg.Add(1)
		go startSnowflakeProxy(config, &wg, shutdown)
	}
	
	// Wait for shutdown signal
	<-sigChan
	fmt.Println("")
	logInfo("Shutting down...")
	close(shutdown)
	
	// Wait for all services to stop
	done := make(chan struct{})
	go func() {
		wg.Wait()
		close(done)
	}()
	
	select {
	case <-done:
		logSuccess("All services stopped gracefully")
	case <-time.After(10 * time.Second):
		logWarn("Forced shutdown after timeout")
	}
}
