package handlers

import (
	"crypto/ed25519"
	"crypto/rand"
	"database/sql"
	"encoding/hex"
	"fmt"
	"net/http"
	"strconv"

	"github.com/Fimeg/RedFlag/aggregator-server/internal/config"
	"github.com/Fimeg/RedFlag/aggregator-server/internal/services"
	"github.com/gin-gonic/gin"
	"github.com/lib/pq"
	_ "github.com/lib/pq"
)

// SetupHandler handles server configuration
type SetupHandler struct {
	configPath string
}

func NewSetupHandler(configPath string) *SetupHandler {
	return &SetupHandler{
		configPath: configPath,
	}
}

// updatePostgresPassword updates the PostgreSQL user password
func updatePostgresPassword(dbHost, dbPort, dbUser, currentPassword, newPassword string) error {
	// Connect to PostgreSQL with current credentials
	connStr := fmt.Sprintf("postgres://%s:%s@%s:%s/postgres?sslmode=disable", dbUser, currentPassword, dbHost, dbPort)

	db, err := sql.Open("postgres", connStr)
	if err != nil {
		return fmt.Errorf("failed to connect to PostgreSQL: %v", err)
	}
	defer db.Close()

	// Test connection
	if err := db.Ping(); err != nil {
		return fmt.Errorf("failed to ping PostgreSQL: %v", err)
	}

	// Update the password
	_, err = db.Exec("ALTER USER "+pq.QuoteIdentifier(dbUser)+" PASSWORD '"+newPassword+"'")
	if err != nil {
		return fmt.Errorf("failed to update PostgreSQL password: %v", err)
	}

	fmt.Println("PostgreSQL password updated successfully")
	return nil
}

// createSharedEnvContentForDisplay generates the .env file content for display
func createSharedEnvContentForDisplay(req struct {
	AdminUser    string `json:"adminUser"`
	AdminPass    string `json:"adminPassword"`
	DBHost       string `json:"dbHost"`
	DBPort       string `json:"dbPort"`
	DBName       string `json:"dbName"`
	DBUser       string `json:"dbUser"`
	DBPassword   string `json:"dbPassword"`
	ServerHost   string `json:"serverHost"`
	ServerPort   string `json:"serverPort"`
	MaxSeats     string `json:"maxSeats"`
}, jwtSecret string, signingKeys map[string]string) (string, error) {
	// Generate .env file content for user to copy
	envContent := fmt.Sprintf(`# RedFlag Environment Configuration
# Generated by web setup on 2025-12-13
# [WARNING] SECURITY CRITICAL: Backup the signing key or you will lose access to all agents

# PostgreSQL Configuration (for PostgreSQL container)
POSTGRES_DB=%s
POSTGRES_USER=%s
POSTGRES_PASSWORD=%s

# RedFlag Security - Ed25519 Signing Keys
# These keys are used to cryptographically sign agent updates and commands
# BACKUP THE PRIVATE KEY IMMEDIATELY - Store it in a secure location like a password manager
REDFLAG_SIGNING_PRIVATE_KEY=%s
REDFLAG_SIGNING_PUBLIC_KEY=%s

# RedFlag Server Configuration
REDFLAG_SERVER_HOST=%s
REDFLAG_SERVER_PORT=%s
REDFLAG_DB_HOST=%s
REDFLAG_DB_PORT=%s
REDFLAG_DB_NAME=%s
REDFLAG_DB_USER=%s
REDFLAG_DB_PASSWORD=%s
REDFLAG_ADMIN_USER=%s
REDFLAG_ADMIN_PASSWORD=%s
REDFLAG_JWT_SECRET=%s
REDFLAG_TOKEN_EXPIRY=24h
REDFLAG_MAX_TOKENS=100
REDFLAG_MAX_SEATS=%s

# Security Settings
REDFLAG_SECURITY_COMMAND_SIGNING_ENFORCEMENT=strict
REDFLAG_SECURITY_NONCE_TIMEOUT=600
REDFLAG_SECURITY_LOG_LEVEL=warn
`,
		req.DBName, req.DBUser, req.DBPassword,
		signingKeys["private_key"], signingKeys["public_key"],
		req.ServerHost, req.ServerPort,
		req.DBHost, req.DBPort, req.DBName, req.DBUser, req.DBPassword,
		req.AdminUser, req.AdminPass, jwtSecret, req.MaxSeats)

	return envContent, nil
}

// ShowSetupPage displays the web setup interface
func (h *SetupHandler) ShowSetupPage(c *gin.Context) {
	// Display setup page - configuration will be generated via web interface
	fmt.Println("Showing setup page - configuration will be generated via web interface")

	html := `
<!DOCTYPE html>
<html>
<head>
    <title>RedFlag - Server Configuration</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; }
        .container { max-width: 800px; margin: 0 auto; padding: 40px 20px; }
        .card { background: white; border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); overflow: hidden; }
        .header { background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%); color: white; padding: 30px; text-align: center; }
        .content { padding: 40px; }
        h1 { margin: 0; font-size: 2.5rem; font-weight: 700; }
        .subtitle { margin: 10px 0 0 0; opacity: 0.9; font-size: 1.1rem; }
        .form-section { margin: 30px 0; }
        .form-section h3 { color: #4f46e5; margin-bottom: 15px; font-size: 1.2rem; }
        .form-group { margin-bottom: 20px; }
        label { display: block; margin-bottom: 5px; font-weight: 500; color: #374151; }
        input, select { width: 100%%; padding: 12px; border: 2px solid #e5e7eb; border-radius: 6px; font-size: 1rem; transition: border-color 0.3s; }
        input:focus, select:focus { outline: none; border-color: #4f46e5; box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1); }
        .btn { background: linear-gradient(135deg, #4f46e5 0%%, #7c3aed 100%%); color: white; border: none; padding: 14px 28px; border-radius: 6px; font-size: 1rem; font-weight: 600; cursor: pointer; transition: transform 0.2s; }
        .btn:hover { transform: translateY(-2px); }
        .btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; }
        .success { color: #10b981; background: #ecfdf5; padding: 12px; border-radius: 6px; border: 1px solid #10b981; }
        .error { color: #ef4444; background: #fef2f2; padding: 12px; border-radius: 6px; border: 1px solid #ef4444; }
        .loading { display: none; text-align: center; margin: 20px 0; }
        .spinner { border: 3px solid #f3f3f3; border-top: 3px solid #4f46e5; border-radius: 50%%; width: 40px; height: 40px; animation: spin 1s linear infinite; margin: 0 auto; }
        @keyframes spin { 0%% { transform: rotate(0deg); } 100%% { transform: rotate(360deg); } }
    </style>
</head>
<body>
    <div class="container">
        <div class="card">
            <div class="header">
                <h1>[START] RedFlag Server Setup</h1>
                <p class="subtitle">Configure your RedFlag deployment</p>
            </div>
            <div class="content">
                <form id="setupForm">
                    <div class="form-section">
                        <h3>📊 Server Configuration</h3>
                        <div class="form-group">
                            <label for="serverHost">Server Host</label>
                            <input type="text" id="serverHost" name="serverHost" value="0.0.0.0" required>
                        </div>
                        <div class="form-group">
                            <label for="serverPort">Server Port</label>
                            <input type="number" id="serverPort" name="serverPort" value="8080" required>
                        </div>
                    </div>

                    <div class="form-section">
                        <h3>🗄️ Database Configuration</h3>
                        <div class="form-group">
                            <label for="dbHost">Database Host</label>
                            <input type="text" id="dbHost" name="dbHost" value="postgres" required>
                        </div>
                        <div class="form-group">
                            <label for="dbPort">Database Port</label>
                            <input type="number" id="dbPort" name="dbPort" value="5432" required>
                        </div>
                        <div class="form-group">
                            <label for="dbName">Database Name</label>
                            <input type="text" id="dbName" name="dbName" value="redflag" required>
                        </div>
                        <div class="form-group">
                            <label for="dbUser">Database User</label>
                            <input type="text" id="dbUser" name="dbUser" value="redflag" required>
                        </div>
                        <div class="form-group">
                            <label for="dbPassword">Database Password</label>
                            <input type="password" id="dbPassword" name="dbPassword" placeholder="Enter a secure database password" required>
                        </div>
                    </div>

                    <div class="form-section">
                        <h3>👤 Administrator Account</h3>
                        <div class="form-group">
                            <label for="adminUser">Admin Username</label>
                            <input type="text" id="adminUser" name="adminUser" value="admin" required>
                        </div>
                        <div class="form-group">
                            <label for="adminPassword">Admin Password</label>
                            <input type="password" id="adminPassword" name="adminPassword" placeholder="Enter a secure admin password" required>
                        </div>
                    </div>

                    <div class="form-section">
                        <h3>🔧 Agent Settings</h3>
                        <div class="form-group">
                            <label for="maxSeats">Maximum Agent Seats</label>
                            <input type="number" id="maxSeats" name="maxSeats" value="50" min="1" max="1000" required>
                            <small style="color: #6b7280; font-size: 0.875rem;">Maximum number of agents that can register</small>
                        </div>
                    </div>

                    <button type="submit" class="btn" id="submitBtn">
                        [START] Configure RedFlag Server
                    </button>
                </form>

                <div class="loading" id="loading">
                    <div class="spinner"></div>
                    <p>Configuring your RedFlag server...</p>
                </div>

                <div id="result"></div>
            </div>
        </div>
    </div>

    <script>
        document.getElementById('setupForm').addEventListener('submit', async function(e) {
            e.preventDefault();

            const submitBtn = document.getElementById('submitBtn');
            const loading = document.getElementById('loading');
            const result = document.getElementById('result');

            // Get form values
            const formData = {
                serverHost: document.getElementById('serverHost').value,
                serverPort: document.getElementById('serverPort').value,
                dbHost: document.getElementById('dbHost').value,
                dbPort: document.getElementById('dbPort').value,
                dbName: document.getElementById('dbName').value,
                dbUser: document.getElementById('dbUser').value,
                dbPassword: document.getElementById('dbPassword').value,
                adminUser: document.getElementById('adminUser').value,
                adminPassword: document.getElementById('adminPassword').value,
                maxSeats: document.getElementById('maxSeats').value
            };

            // Validate inputs
            if (!formData.adminUser || !formData.adminPassword) {
                result.innerHTML = '<div class="error">[ERROR] Admin username and password are required</div>';
                return;
            }

            if (!formData.dbHost || !formData.dbPort || !formData.dbName || !formData.dbUser || !formData.dbPassword) {
                result.innerHTML = '<div class="error">[ERROR] All database fields are required</div>';
                return;
            }

            // Show loading
            submitBtn.disabled = true;
            loading.style.display = 'block';
            result.innerHTML = '';

            try {
                const response = await fetch('/api/setup/configure', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify(formData)
                });

                const resultData = await response.json();

                if (response.ok) {
                    let resultHtml = '<div class="success">';
                    resultHtml += '<h3>[SUCCESS] Configuration Generated Successfully!</h3>';
                    resultHtml += '<p><strong>Your JWT Secret:</strong> <code style="background: #f3f4f6; padding: 2px 6px; border-radius: 3px;">' + resultData.jwtSecret + '</code> ';
                    resultHtml += '<button onclick="copyJWT(\'' + resultData.jwtSecret + '\')" style="background: #4f46e5; color: white; border: none; padding: 4px 8px; border-radius: 3px; cursor: pointer; font-size: 0.8rem;">📋 Copy</button></p>';
                    resultHtml += '<p><strong>[WARNING] Important Next Steps:</strong></p>';
                    resultHtml += '<div style="background: #fef3c7; border: 1px solid #f59e0b; border-radius: 6px; padding: 15px; margin: 15px 0;">';
                    resultHtml += '<p style="margin: 0; color: #92400e;"><strong>🔧 Complete Setup Required:</strong></p>';
                    resultHtml += '<ol style="margin: 10px 0 0 0; color: #92400e;">';
                    resultHtml += '<li>Replace the bootstrap environment variables with the newly generated ones below</li>';
                    resultHtml += '<li>Run: <code style="background: #fef3c7; padding: 2px 6px; border-radius: 3px;">' + resultData.manualRestartCommand + '</code></li>';
                    resultHtml += '</ol>';
                    resultHtml += '<p style="margin: 10px 0 0 0; color: #92400e; font-size: 0.9rem;"><strong>This step is required to apply your configuration and run database migrations.</strong></p>';
                    resultHtml += '</div>';
                    resultHtml += '</div>';

                    resultHtml += '<div style="margin-top: 20px;">';
                    resultHtml += '<h4>📄 Configuration Content:</h4>';
                    resultHtml += '<textarea readonly style="width: 100%%; height: 300px; font-family: monospace; font-size: 0.85rem; padding: 10px; border: 1px solid #d1d5db; border-radius: 6px; background: #f9fafb;">' + resultData.envContent + '</textarea>';
                    resultHtml += '<button onclick="copyConfig()" style="background: #10b981; color: white; border: none; padding: 8px 16px; border-radius: 6px; cursor: pointer; margin-top: 10px;">📋 Copy All Configuration</button>';
                    resultHtml += '</div>';

                    result.innerHTML = resultHtml;
                    loading.style.display = 'none';

                    // Store JWT for copy function
                    window.jwtSecret = resultData.jwtSecret;
                    window.envContent = resultData.envContent;

                } else {
                    result.innerHTML = '<div class="error">[ERROR] Error: ' + resultData.error + '</div>';
                    submitBtn.disabled = false;
                    loading.style.display = 'none';
                }
            } catch (error) {
                result.innerHTML = '<div class="error">[ERROR] Network error: ' + error.message + '</div>';
                submitBtn.disabled = false;
                loading.style.display = 'none';
            }
        });

        function copyJWT(jwt) {
            navigator.clipboard.writeText(jwt).then(() => {
                alert('JWT secret copied to clipboard!');
            }).catch(() => {
                prompt('Copy this JWT secret:', jwt);
            });
        }

        function copyConfig() {
            if (window.envContent) {
                navigator.clipboard.writeText(window.envContent).then(() => {
                    alert('Configuration copied to clipboard!');
                }).catch(() => {
                    prompt('Copy this configuration:', window.envContent);
                });
            }
        }
    </script>
</body>
</html>`
	c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(html))
}

// ConfigureServer handles the configuration submission
func (h *SetupHandler) ConfigureServer(c *gin.Context) {
	var req struct {
		AdminUser    string `json:"adminUser"`
		AdminPass    string `json:"adminPassword"`
		DBHost       string `json:"dbHost"`
		DBPort       string `json:"dbPort"`
		DBName       string `json:"dbName"`
		DBUser       string `json:"dbUser"`
		DBPassword   string `json:"dbPassword"`
		ServerHost   string `json:"serverHost"`
		ServerPort   string `json:"serverPort"`
		MaxSeats     string `json:"maxSeats"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request format"})
		return
	}

	// Validate inputs
	if req.AdminUser == "" || req.AdminPass == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Admin username and password are required"})
		return
	}

	if req.DBHost == "" || req.DBPort == "" || req.DBName == "" || req.DBUser == "" || req.DBPassword == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "All database fields are required"})
		return
	}

	// Parse numeric values
	dbPort, err := strconv.Atoi(req.DBPort)
	if err != nil || dbPort <= 0 || dbPort > 65535 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid database port"})
		return
	}

	serverPort, err := strconv.Atoi(req.ServerPort)
	if err != nil || serverPort <= 0 || serverPort > 65535 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid server port"})
		return
	}

	maxSeats, err := strconv.Atoi(req.MaxSeats)
	if err != nil || maxSeats <= 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid maximum agent seats"})
		return
	}

	// Generate secure JWT secret (not derived from credentials for security)
	jwtSecret, err := config.GenerateSecureToken()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate JWT secret"})
		return
	}

	// SECURITY: Generate Ed25519 signing keypair (critical for v0.2.x)
	fmt.Println("[START] Generating Ed25519 signing keypair for security...")
	signingPublicKey, signingPrivateKey, err := ed25519.GenerateKey(rand.Reader)
	if err != nil {
		fmt.Printf("CRITICAL ERROR: Failed to generate signing keys: %v\n", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate signing keys. Security features cannot be enabled."})
		return
	}

	signingKeys := map[string]string{
		"public_key":  hex.EncodeToString(signingPublicKey),
		"private_key": hex.EncodeToString(signingPrivateKey),
	}
	fmt.Printf("[SUCCESS] Generated Ed25519 keypair - Fingerprint: %s\n", signingKeys["public_key"][:16])
	fmt.Println("[WARNING]  SECURITY WARNING: Backup the private key immediately or you will lose access to all agents!")

	// Step 1: Update PostgreSQL password from bootstrap to user password
	fmt.Println("Updating PostgreSQL password from bootstrap to user-provided password...")
	bootstrapPassword := "redflag_bootstrap"  // This matches our bootstrap .env
	if err := updatePostgresPassword(req.DBHost, req.DBPort, req.DBUser, bootstrapPassword, req.DBPassword); err != nil {
		fmt.Printf("CRITICAL ERROR: Failed to update PostgreSQL password: %v\n", err)
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "Failed to update database password. Setup cannot continue.",
			"details": err.Error(),
			"help": "Ensure PostgreSQL is accessible and the bootstrap password is correct. Check Docker logs for details.",
		})
		return
	}
	fmt.Println("PostgreSQL password successfully updated from bootstrap to user-provided password")

	// Step 2: Generate configuration content for manual update
	fmt.Println("Generating configuration content for manual .env file update...")

	// Generate the complete .env file content for the user to copy
	newEnvContent, err := createSharedEnvContentForDisplay(req, jwtSecret, signingKeys)
	if err != nil {
		fmt.Printf("Failed to generate .env content: %v\n", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate configuration content"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"message": "Configuration generated successfully!",
		"envContent": newEnvContent,
		"restartMessage": "Please replace the bootstrap environment variables with the newly generated ones, then run: docker-compose down && docker-compose up -d",
		"manualRestartRequired": true,
		"manualRestartCommand": "docker-compose down && docker-compose up -d",
		"configFilePath": "./config/.env",
		"securityNotice": "[WARNING] A signing key has been generated. BACKUP THE PRIVATE KEY or you will lose access to all agents!",
		"publicKeyFingerprint": signingKeys["public_key"][:16] + "...",
	})
}

// GenerateSigningKeys generates Ed25519 keypair for agent update signing
func (h *SetupHandler) GenerateSigningKeys(c *gin.Context) {
	// Prevent caching of generated keys (security critical)
	c.Header("Cache-Control", "no-store, no-cache, must-revalidate, private")
	c.Header("Pragma", "no-cache")
	c.Header("Expires", "0")

	// Load configuration to check for existing key
	cfg, err := config.Load() // This will load from .env file
	if err == nil && cfg.SigningPrivateKey != "" {
		c.JSON(http.StatusConflict, gin.H{"error": "A signing key is already configured for this server."})
		return
	}

	// Generate Ed25519 keypair
	publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to generate keypair"})
		return
	}

	// Encode to hex
	publicKeyHex := hex.EncodeToString(publicKey)
	privateKeyHex := hex.EncodeToString(privateKey)

	// Generate fingerprint (first 16 chars)
	fingerprint := publicKeyHex[:16]

	// Log key generation for security audit trail (only fingerprint, not full key)
	fmt.Printf("Generated new Ed25519 keypair - Fingerprint: %s\n", fingerprint)

	c.JSON(http.StatusOK, gin.H{
		"public_key":  publicKeyHex,
		"private_key": privateKeyHex,
		"fingerprint": fingerprint,
		"algorithm":   "ed25519",
		"key_size":    32,
	})
}


// ConfigureSecrets creates all Docker secrets automatically
func (h *SetupHandler) ConfigureSecrets(c *gin.Context) {
	// Check if Docker API is available
	if !services.IsDockerAvailable() {
		c.JSON(http.StatusServiceUnavailable, gin.H{
			"error": "Docker API not available",
			"message": "Docker socket is not mounted. Please ensure the server can access Docker daemon",
		})
		return
	}

	// Create Docker secrets service
	dockerSecrets, err := services.NewDockerSecretsService()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "Failed to connect to Docker",
			"details": err.Error(),
		})
		return
	}
	defer dockerSecrets.Close()

	// Generate all required secrets
	type SecretConfig struct {
		Name  string
		Value string
	}

	secrets := []SecretConfig{
		{"redflag_admin_password", config.GenerateSecurePassword()},
		{"redflag_jwt_secret", generateSecureJWTSecret()},
		{"redflag_db_password", config.GenerateSecurePassword()},
	}

	// Try to create each secret
	createdSecrets := []string{}
	failedSecrets := []string{}

	for _, secret := range secrets {
		if err := dockerSecrets.CreateSecret(secret.Name, secret.Value); err != nil {
			failedSecrets = append(failedSecrets, fmt.Sprintf("%s: %v", secret.Name, err))
		} else {
			createdSecrets = append(createdSecrets, secret.Name)
		}
	}

	// Generate signing keys
	publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "Failed to generate signing keys",
			"details": err.Error(),
		})
		return
	}

	publicKeyHex := hex.EncodeToString(publicKey)
	privateKeyHex := hex.EncodeToString(privateKey)

	// Create signing key secret
	if err := dockerSecrets.CreateSecret("redflag_signing_private_key", privateKeyHex); err != nil {
		failedSecrets = append(failedSecrets, fmt.Sprintf("redflag_signing_private_key: %v", err))
	} else {
		createdSecrets = append(createdSecrets, "redflag_signing_private_key")
	}

	response := gin.H{
		"created_secrets": createdSecrets,
		"public_key":      publicKeyHex,
		"fingerprint":     publicKeyHex[:16],
	}

	if len(failedSecrets) > 0 {
		response["failed_secrets"] = failedSecrets
		c.JSON(http.StatusMultiStatus, response)
		return
	}

	c.JSON(http.StatusOK, response)
}

// GenerateSecurePassword generates a secure password for admin/db
func generateSecurePassword() string {
	bytes := make([]byte, 16)
	rand.Read(bytes)
	return hex.EncodeToString(bytes)[:16] // 16 character random password
}

// generateSecureJWTSecret generates a secure JWT secret
func generateSecureJWTSecret() string {
	bytes := make([]byte, 32)
	rand.Read(bytes)
	return hex.EncodeToString(bytes)
}
