package com.saas.shared.mcp.client;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.saas.shared.mcp.config.Context7McpConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * Context7 MCP HTTP Client
 * Handles communication with Context7 MCP server for dependency resolution
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class Context7McpClient {

    private final Context7McpConfig config;
    private final ObjectMapper objectMapper;
    private final HttpClient httpClient = HttpClient.newBuilder()
            .connectTimeout(Duration.ofMillis(30000))
            .build();

    /**
     * Get library documentation from Context7
     */
    public String getLibraryDocs(String libraryId) {
        if (!config.isEnabled()) {
            log.warn("Context7 MCP is disabled");
            return null;
        }

        try {
            Map<String, Object> payload = new HashMap<>();
            payload.put("tool", "get-library-docs");
            payload.put("library_id", libraryId);

            return callContext7Api(payload);
        } catch (Exception e) {
            log.error("❌ Error getting library docs for {}: {}", libraryId, e.getMessage(), e);
            return null;
        }
    }

    /**
     * Resolve library ID from Context7
     */
    public String resolveLibraryId(String libraryName, String version) {
        if (!config.isEnabled()) {
            log.warn("Context7 MCP is disabled");
            return null;
        }

        try {
            Map<String, Object> payload = new HashMap<>();
            payload.put("tool", "resolve-library-id");
            payload.put("name", libraryName);
            payload.put("version", version);

            return callContext7Api(payload);
        } catch (Exception e) {
            log.error("❌ Error resolving library ID for {} {}: {}", libraryName, version, e.getMessage(), e);
            return null;
        }
    }

    /**
     * Call Context7 MCP API with retry logic
     */
    private String callContext7Api(Map<String, Object> payload) throws Exception {
        int attempts = 0;
        Exception lastException = null;

        while (attempts < config.getMaxRetries()) {
            try {
                attempts++;
                log.info("📡 Calling Context7 MCP (attempt {}/{})", attempts, config.getMaxRetries());

                String jsonPayload = objectMapper.writeValueAsString(payload);

                HttpRequest request = HttpRequest.newBuilder()
                        .uri(URI.create(config.getUrl()))
                        .timeout(Duration.ofMillis(config.getTimeout()))
                        .header("Content-Type", "application/json")
                        .header("CONTEXT7_API_KEY", config.getApiKey())
                        .header("User-Agent", "SaaS-VoIP-Platform/1.0")
                        .POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
                        .build();

                HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

                if (response.statusCode() == 200) {
                    log.info("✅ Context7 MCP call successful");
                    return response.body();
                } else {
                    log.warn("⚠️ Context7 MCP returned status {}: {}", response.statusCode(), response.body());
                    lastException = new RuntimeException("HTTP " + response.statusCode());
                }
            } catch (Exception e) {
                lastException = e;
                log.warn("⚠️ Context7 MCP call failed (attempt {}): {}", attempts, e.getMessage());
                if (attempts < config.getMaxRetries()) {
                    Thread.sleep(1000 * attempts); // Exponential backoff
                }
            }
        }

        throw new RuntimeException("Failed to call Context7 MCP after " + attempts + " attempts", lastException);
    }

    /**
     * Check if Context7 MCP is available and configured
     */
    public boolean isAvailable() {
        return config.isEnabled() && config.getApiKey() != null && !config.getApiKey().isEmpty();
    }
}
