package com.saas.shared.service;

import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * BaseUrlResolver - Centralized URL resolution service
 * 
 * Resolves the base URL for webhook callbacks and WebSocket endpoints
 * in a consistent, environment-aware manner across all VoIP controllers.
 * 
 * Priority Order:
 * 1. BASE_URL environment variable (production VPS, explicit override)
 * 2. REPLIT_DOMAINS environment variable (Replit deployments)
 * 3. HTTP request headers (X-Forwarded-Proto, X-Forwarded-Host, Host)
 * 4. Fallback to ngrok URL (development only)
 * 
 * Usage Examples:
 * 
 * In Controllers (with HttpServletRequest available):
 * -----------------------------------------------
 * String baseUrl = baseUrlResolver.resolveBaseUrl(request);
 * String wsUrl = baseUrlResolver.resolveWebSocketUrl(request);
 * 
 * In Services (without HttpServletRequest):
 * -----------------------------------------
 * String baseUrl = baseUrlResolver.resolveBaseUrl();
 * 
 * Production VPS Setup:
 * ---------------------
 * Set BASE_URL environment variable in your .env or docker-compose.yml:
 * BASE_URL=https://your-production-domain.com
 * 
 * This eliminates the need for manual URL changes during deployment.
 */
@Service
@Slf4j
public class BaseUrlResolver {

    @Value("${server.base-url:#{null}}")
    private String configuredBaseUrl;
    
    @Value("${server.fallback-url:https://your-domain.com}")
    private String fallbackUrl;
    
    /**
     * Resolve base URL using HttpServletRequest headers
     * This is the PREFERRED method when HttpServletRequest is available
     * 
     * @param request HttpServletRequest with headers
     * @return Resolved base URL (e.g., "https://your-domain.com")
     */
    public String resolveBaseUrl(HttpServletRequest request) {
        // Priority 1: Explicit BASE_URL environment variable
        String baseUrl = getExplicitBaseUrl();
        if (baseUrl != null) {
            log.debug("🎯 Using explicit BASE_URL: {}", baseUrl);
            return baseUrl;
        }
        
        // Priority 2: REPLIT_DOMAINS environment variable
        baseUrl = getReplitDomains();
        if (baseUrl != null) {
            log.debug("🎯 Using REPLIT_DOMAINS: {}", baseUrl);
            return baseUrl;
        }
        
        // Priority 3: HTTP request headers (X-Forwarded-* or Host)
        if (request != null) {
            baseUrl = resolveFromRequestHeaders(request);
            if (baseUrl != null) {
                log.debug("🎯 Resolved from request headers: {}", baseUrl);
                return baseUrl;
            }
        }
        
        // Priority 4: Fallback URL from configuration (development only)
        log.warn("⚠️ Using fallback URL from configuration - Set BASE_URL env var for production!");
        return fallbackUrl;
    }
    
    /**
     * Resolve base URL without HttpServletRequest
     * Use this when request context is not available (e.g., async services)
     * 
     * @return Resolved base URL
     */
    public String resolveBaseUrl() {
        return resolveBaseUrl(null);
    }
    
    /**
     * Resolve WebSocket URL (wss://) from base URL
     * 
     * @param request HttpServletRequest
     * @return WebSocket URL with wss:// protocol
     */
    public String resolveWebSocketUrl(HttpServletRequest request) {
        String baseUrl = resolveBaseUrl(request);
        return convertToWebSocketUrl(baseUrl);
    }
    
    /**
     * Resolve WebSocket URL without HttpServletRequest
     * 
     * @return WebSocket URL with wss:// protocol
     */
    public String resolveWebSocketUrl() {
        return resolveWebSocketUrl(null);
    }
    
    /**
     * Build a complete callback URL from base URL and path
     * 
     * @param request HttpServletRequest
     * @param path Callback path (e.g., "/api/voip/twilio/status-callback")
     * @return Complete callback URL
     */
    public String buildCallbackUrl(HttpServletRequest request, String path) {
        String baseUrl = resolveBaseUrl(request);
        return normalizeUrl(baseUrl, path);
    }
    
    /**
     * Build a complete callback URL without HttpServletRequest
     * 
     * @param path Callback path
     * @return Complete callback URL
     */
    public String buildCallbackUrl(String path) {
        return buildCallbackUrl(null, path);
    }
    
    /**
     * Build a complete WebSocket URL with path
     * 
     * @param request HttpServletRequest
     * @param path WebSocket path (e.g., "/api/voip/gemini/conversation")
     * @return Complete WebSocket URL with wss://
     */
    public String buildWebSocketUrl(HttpServletRequest request, String path) {
        String wsBaseUrl = resolveWebSocketUrl(request);
        return normalizeUrl(wsBaseUrl, path);
    }
    
    /**
     * Build a complete WebSocket URL without HttpServletRequest
     * 
     * @param path WebSocket path
     * @return Complete WebSocket URL with wss://
     */
    public String buildWebSocketUrl(String path) {
        return buildWebSocketUrl(null, path);
    }
    
    // ========== PRIVATE HELPER METHODS ==========
    
    /**
     * Get explicit BASE_URL from environment variables or application.properties
     */
    private String getExplicitBaseUrl() {
        // Check application.properties first (via @Value)
        if (configuredBaseUrl != null && !configuredBaseUrl.isEmpty()) {
            return normalizeProtocol(configuredBaseUrl);
        }
        
        // Check environment variable
        String envBaseUrl = System.getenv("BASE_URL");
        if (envBaseUrl != null && !envBaseUrl.isEmpty()) {
            return normalizeProtocol(envBaseUrl);
        }
        
        return null;
    }
    
    /**
     * Get REPLIT_DOMAINS environment variable
     * Handles comma-separated domains (takes first one)
     */
    private String getReplitDomains() {
        String replitDomains = System.getenv("REPLIT_DOMAINS");
        if (replitDomains != null && !replitDomains.isEmpty()) {
            // Extract first domain if multiple
            if (replitDomains.contains(",")) {
                replitDomains = replitDomains.split(",")[0].trim();
            }
            return normalizeProtocol(replitDomains);
        }
        return null;
    }
    
    /**
     * Resolve base URL from HTTP request headers
     * Respects X-Forwarded-Proto and X-Forwarded-Host for proxy environments
     */
    private String resolveFromRequestHeaders(HttpServletRequest request) {
        if (request == null) {
            return null;
        }
        
        // Get protocol (http/https)
        String protocol = request.getHeader("X-Forwarded-Proto");
        if (protocol == null || protocol.isEmpty()) {
            protocol = request.getScheme();
        }
        
        // Get host (domain:port)
        String host = request.getHeader("X-Forwarded-Host");
        if (host == null || host.isEmpty()) {
            host = request.getHeader("Host");
        }
        
        if (host != null && !host.isEmpty()) {
            return protocol + "://" + host;
        }
        
        return null;
    }
    
    /**
     * Normalize protocol to https:// for external URLs
     */
    private String normalizeProtocol(String url) {
        if (url == null || url.isEmpty()) {
            return url;
        }
        
        // Add https:// prefix if missing
        if (!url.startsWith("http://") && !url.startsWith("https://")) {
            return "https://" + url;
        }
        
        return url;
    }
    
    /**
     * Convert HTTP URL to WebSocket URL (https:// → wss://, http:// → ws://)
     */
    private String convertToWebSocketUrl(String httpUrl) {
        if (httpUrl == null || httpUrl.isEmpty()) {
            return httpUrl;
        }
        
        return httpUrl
                .replace("https://", "wss://")
                .replace("http://", "ws://");
    }
    
    /**
     * Normalize URL by combining base URL and path
     * Handles trailing/leading slashes correctly
     */
    private String normalizeUrl(String baseUrl, String path) {
        if (baseUrl == null || baseUrl.isEmpty()) {
            return path;
        }
        
        if (path == null || path.isEmpty()) {
            return baseUrl;
        }
        
        // Remove trailing slash from baseUrl
        String normalizedBase = baseUrl.endsWith("/") 
            ? baseUrl.substring(0, baseUrl.length() - 1) 
            : baseUrl;
        
        // Ensure path starts with slash
        String normalizedPath = path.startsWith("/") ? path : "/" + path;
        
        return normalizedBase + normalizedPath;
    }
}
