package com.saas.voip.service;

import com.saas.voip.dto.CallResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;

/**
 * Retell AI API Client
 * 
 * Phase 4.1 - REST client for Retell AI platform
 * Updated December 2025 - API V2 endpoints
 * 
 * Capabilities:
 * - Create/update/delete voice agents
 * - Initiate outbound calls
 * - Get call details and status
 * - List agents and calls
 * 
 * API Reference: https://docs.retellai.com/api-references
 * API Version: V2 (V1 deprecated February 2025)
 * Cost: $0.07/minute base + LLM/TTS costs
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class RetellApiClient {

    private final RestTemplate restTemplate;

    @Value("${retell.api.key}")
    private String retellApiKey;

    @Value("${retell.api.base-url:https://api.retellai.com}")
    private String retellBaseUrl;

    /**
     * Create Retell Agent
     * API V2: POST /v2/create-agent
     * 
     * @param agentConfig Agent configuration (name, voice, LLM model, prompt)
     * @return Created agent with agent_id
     */
    public Map<String, Object> createAgent(Map<String, Object> agentConfig) {
        log.info("🚀 Creating Retell agent: {}", agentConfig.get("agent_name"));

        String url = retellBaseUrl + "/v2/create-agent";

        HttpHeaders headers = createAuthHeaders();
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(agentConfig, headers);

        try {
            ResponseEntity<Map> response = restTemplate.exchange(
                    url,
                    HttpMethod.POST,
                    request,
                    Map.class);

            Map<String, Object> agent = response.getBody();
            log.info("✅ Retell agent created - ID: {}", agent.get("agent_id"));

            return agent;

        } catch (Exception e) {
            log.error("❌ Failed to create Retell agent", e);
            throw new RuntimeException("Retell agent creation failed: " + e.getMessage(), e);
        }
    }

    /**
     * Initiate outbound call via Retell AI
     * API V2: POST /v2/create-phone-call
     * 
     * @param fromNumber       Caller phone number (E.164 format) - REQUIRED
     * @param toNumber         Target phone number (E.164 format) - REQUIRED
     * @param agentId          Retell agent ID (optional override)
     * @param metadata         Optional metadata for the call
     * @param dynamicVariables Optional dynamic variables for LLM context
     * @return Call details with call_id
     */
    public CallResponse initiateCall(String fromNumber, String toNumber, String agentId,
            Map<String, Object> metadata, Map<String, Object> dynamicVariables) {
        log.info("📞 Initiating Retell call - From: {}, To: {}, Agent: {}", fromNumber, toNumber, agentId);

        String url = retellBaseUrl + "/v2/create-phone-call";

        Map<String, Object> callRequest = new HashMap<>();
        callRequest.put("from_number", fromNumber);
        callRequest.put("to_number", toNumber);

        if (agentId != null && !agentId.isEmpty()) {
            callRequest.put("override_agent_id", agentId);
        }

        if (metadata != null && !metadata.isEmpty()) {
            callRequest.put("metadata", metadata);
        }

        if (dynamicVariables != null && !dynamicVariables.isEmpty()) {
            callRequest.put("retell_llm_dynamic_variables", dynamicVariables);
        }

        HttpHeaders headers = createAuthHeaders();
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(callRequest, headers);

        try {
            ResponseEntity<Map> response = restTemplate.exchange(
                    url,
                    HttpMethod.POST,
                    request,
                    Map.class);

            Map<String, Object> callData = response.getBody();
            String callId = (String) callData.get("call_id");
            String status = (String) callData.get("call_status");

            log.info("✅ Retell call initiated - Call ID: {}, Status: {}", callId, status);

            return CallResponse.builder()
                    .callId(callId)
                    .provider("RETELL")
                    .status(status)
                    .phoneNumber(toNumber)
                    .message("Call initiated successfully")
                    .build();

        } catch (Exception e) {
            log.error("❌ Failed to initiate Retell call", e);
            throw new RuntimeException("Retell call initiation failed: " + e.getMessage(), e);
        }
    }

    /**
     * Initiate outbound call (simplified - for backward compatibility)
     * Requires from_number to be configured on phone number in Retell dashboard
     */
    public CallResponse initiateCall(String fromNumber, String toNumber, String agentId) {
        return initiateCall(fromNumber, toNumber, agentId, null, null);
    }

    /**
     * Get call details
     * API V2: GET /v2/get-call?call_id={callId}
     * 
     * @param callId Retell call ID
     * @return Call details (status, transcript, duration, cost, analysis)
     */
    public Map<String, Object> getCallDetails(String callId) {
        log.debug("📊 Fetching Retell call details - ID: {}", callId);

        String url = retellBaseUrl + "/v2/get-call?call_id=" + callId;

        HttpHeaders headers = createAuthHeaders();
        HttpEntity<?> request = new HttpEntity<>(headers);

        try {
            ResponseEntity<Map> response = restTemplate.exchange(
                    url,
                    HttpMethod.GET,
                    request,
                    Map.class);

            return response.getBody();

        } catch (Exception e) {
            log.error("❌ Failed to fetch Retell call details", e);
            throw new RuntimeException("Failed to get call details: " + e.getMessage(), e);
        }
    }

    /**
     * Get call status (simplified)
     * 
     * @param callId Retell call ID
     * @return Call status (registered, ongoing, ended, error)
     */
    public String getCallStatus(String callId) {
        Map<String, Object> callDetails = getCallDetails(callId);
        return (String) callDetails.get("call_status");
    }

    /**
     * Get agent details
     * API: GET /get-agent?agent_id={agentId}
     * 
     * @param agentId Retell agent ID
     * @return Agent configuration
     */
    public Map<String, Object> getAgent(String agentId) {
        log.debug("🔍 Fetching Retell agent - ID: {}", agentId);

        String url = retellBaseUrl + "/v2/get-agent?agent_id=" + agentId;

        HttpHeaders headers = createAuthHeaders();
        HttpEntity<?> request = new HttpEntity<>(headers);

        try {
            ResponseEntity<Map> response = restTemplate.exchange(
                    url,
                    HttpMethod.GET,
                    request,
                    Map.class);

            return response.getBody();

        } catch (Exception e) {
            log.error("❌ Failed to fetch Retell agent", e);
            throw new RuntimeException("Failed to get agent: " + e.getMessage(), e);
        }
    }

    /**
     * List all agents
     * API: GET /list-agents
     * 
     * @return List of agents
     */
    public java.util.List<Map<String, Object>> listAgents() {
        log.debug("📋 Listing Retell agents");

        String url = retellBaseUrl + "/list-agents";

        HttpHeaders headers = createAuthHeaders();
        HttpEntity<?> request = new HttpEntity<>(headers);

        try {
            ResponseEntity<java.util.List> response = restTemplate.exchange(
                    url,
                    HttpMethod.GET,
                    request,
                    java.util.List.class);

            return response.getBody();

        } catch (Exception e) {
            log.error("❌ Failed to list Retell agents", e);
            throw new RuntimeException("Failed to list agents: " + e.getMessage(), e);
        }
    }

    /**
     * List calls with filters
     * API V2: POST /v2/list-calls
     * 
     * @param filters Filter criteria (agent_id, start_timestamp, end_timestamp,
     *                limit)
     * @return List of calls
     */
    public Map<String, Object> listCalls(Map<String, Object> filters) {
        log.debug("📋 Listing Retell calls");

        String url = retellBaseUrl + "/v2/list-calls";

        HttpHeaders headers = createAuthHeaders();
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(filters != null ? filters : new HashMap<>(),
                headers);

        try {
            ResponseEntity<Map> response = restTemplate.exchange(
                    url,
                    HttpMethod.POST,
                    request,
                    Map.class);

            return response.getBody();

        } catch (Exception e) {
            log.error("❌ Failed to list Retell calls", e);
            throw new RuntimeException("Failed to list calls: " + e.getMessage(), e);
        }
    }

    /**
     * Update agent configuration
     * API: PATCH /update-agent
     * 
     * @param agentId Retell agent ID
     * @param updates Fields to update
     * @return Updated agent
     */
    public Map<String, Object> updateAgent(String agentId, Map<String, Object> updates) {
        log.info("✏️ Updating Retell agent: {}", agentId);

        String url = retellBaseUrl + "/v2/update-agent";

        updates.put("agent_id", agentId);

        HttpHeaders headers = createAuthHeaders();
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(updates, headers);

        try {
            ResponseEntity<Map> response = restTemplate.exchange(
                    url,
                    HttpMethod.PATCH,
                    request,
                    Map.class);

            log.info("✅ Retell agent updated - ID: {}", agentId);
            return response.getBody();

        } catch (Exception e) {
            log.error("❌ Failed to update Retell agent", e);
            throw new RuntimeException("Agent update failed: " + e.getMessage(), e);
        }
    }

    /**
     * Delete agent
     * API: DELETE /delete-agent?agent_id={agentId}
     * 
     * @param agentId Retell agent ID
     */
    public void deleteAgent(String agentId) {
        log.warn("🗑️ Deleting Retell agent: {}", agentId);

        String url = retellBaseUrl + "/v2/delete-agent?agent_id=" + agentId;

        HttpHeaders headers = createAuthHeaders();
        HttpEntity<?> request = new HttpEntity<>(headers);

        try {
            restTemplate.exchange(
                    url,
                    HttpMethod.DELETE,
                    request,
                    Void.class);

            log.info("✅ Retell agent deleted - ID: {}", agentId);

        } catch (Exception e) {
            log.error("❌ Failed to delete Retell agent", e);
            throw new RuntimeException("Agent deletion failed: " + e.getMessage(), e);
        }
    }

    /**
     * End active call
     * API V2: POST /v2/end-call
     * 
     * @param callId Retell call ID
     */
    public void endCall(String callId) {
        log.warn("🛑 Ending Retell call: {}", callId);

        String url = retellBaseUrl + "/v2/end-call";

        Map<String, Object> payload = new HashMap<>();
        payload.put("call_id", callId);

        HttpHeaders headers = createAuthHeaders();
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(payload, headers);

        try {
            restTemplate.exchange(
                    url,
                    HttpMethod.POST,
                    request,
                    Void.class);

            log.info("✅ Retell call ended - ID: {}", callId);

        } catch (Exception e) {
            log.error("❌ Failed to end Retell call", e);
            throw new RuntimeException("Call termination failed: " + e.getMessage(), e);
        }
    }

    /**
     * @deprecated Use endCall instead
     */
    @Deprecated
    public void terminateCall(String callId) {
        endCall(callId);
    }

    /**
     * Create HTTP headers with Retell API authentication
     */
    private HttpHeaders createAuthHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Authorization", "Bearer " + retellApiKey);
        headers.set("Content-Type", "application/json");
        return headers;
    }

    /**
     * Update agent knowledge base (for AI Knowledge Base system)
     * 
     * @param agentId      Retell agent ID
     * @param systemPrompt System prompt to update
     * @param ragDocument  RAG document content
     */
    public void updateAgentKnowledge(String agentId, String systemPrompt, String ragDocument) {
        log.info("🔄 Updating knowledge for Retell agent: {}", agentId);

        try {
            // Build update payload
            Map<String, Object> payload = new HashMap<>();
            payload.put("general_prompt", systemPrompt);

            // Add knowledge base as a tool
            Map<String, Object> knowledgeTool = new HashMap<>();
            knowledgeTool.put("type", "knowledge_base");

            Map<String, Object> knowledgeBase = new HashMap<>();
            knowledgeBase.put("documents", java.util.List.of(ragDocument));
            knowledgeTool.put("knowledge_base", knowledgeBase);

            payload.put("general_tools", java.util.List.of(knowledgeTool));

            // Call Retell API
            HttpHeaders headers = createAuthHeaders();
            HttpEntity<Map<String, Object>> request = new HttpEntity<>(payload, headers);

            String url = retellBaseUrl + "/v2/agent/" + agentId;
            ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.PATCH, request, Map.class);

            if (response.getStatusCode().is2xxSuccessful()) {
                log.info("✅ Retell agent knowledge updated successfully");
            } else {
                log.error("❌ Failed to update Retell agent knowledge. Status: {}", response.getStatusCode());
            }

        } catch (Exception e) {
            log.error("❌ Error updating Retell agent knowledge", e);
            throw new RuntimeException("Failed to update Retell agent knowledge", e);
        }
    }
}
