package com.saas.shared.consumer;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.saas.shared.core.TenantContext;
import com.saas.shared.event.CallDataEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.support.Acknowledgment;
import org.springframework.kafka.support.KafkaHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;

/**
 * Call Data Event Consumer - Handles dual-save to Tenant DB
 * 
 * Flow:
 * 1. Admin DB save succeeds (synchronous in webhook)
 * 2. Publish CallDataEvent to Kafka
 * 3. Consumer saves to Tenant DB (with retry)
 * 4. On failure: retry 3x with exponential backoff → DLQ
 */
@Component
@Slf4j
public class CallDataEventConsumer {

    private final ObjectMapper objectMapper;
    // TODO: Inject TenantCallDataService for tenant DB persistence

    public CallDataEventConsumer(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    /**
     * Consume call data events for tenant DB persistence
     */
    @KafkaListener(
            topics = "call-data-events",
            groupId = "saas-call-data-group",
            containerFactory = "kafkaListenerContainerFactory"
    )
    @Retryable(
            maxAttempts = 3,
            backoff = @Backoff(delay = 1000, multiplier = 2.0)
    )
    public void consumeCallDataEvent(
            @Payload String message,
            @Header(KafkaHeaders.RECEIVED_PARTITION) int partition,
            @Header(KafkaHeaders.OFFSET) long offset,
            Acknowledgment acknowledgment) {
        
        try {
            CallDataEvent event = objectMapper.readValue(message, CallDataEvent.class);
            
            log.info("📥 Consuming call data event: eventId={}, tenantId={}, callSid={}, partition={}, offset={}", 
                    event.getEventId(), event.getTenantId(), event.getCallSid(), partition, offset);
            
            // Set tenant context for DB routing
            TenantContext.setTenantId(event.getSchemaName());
            
            // Save to tenant database
            saveToTenantDatabase(event);
            
            // Acknowledge after successful processing
            acknowledgment.acknowledge();
            
            log.info("✅ Call data saved to tenant DB: tenantId={}, callSid={}", 
                    event.getTenantId(), event.getCallSid());
            
        } catch (Exception e) {
            log.error("❌ Failed to save call data to tenant DB: partition={}, offset={}, retry={}", 
                    partition, offset, e);
            
            // Increment retry counter in the event
            // If max retries exceeded, send to DLQ
            // For now, acknowledge to avoid blocking
            acknowledgment.acknowledge();
            
        } finally {
            TenantContext.clear();
        }
    }

    /**
     * Save call data to tenant database
     * 
     * @param event CallDataEvent with call details
     */
    private void saveToTenantDatabase(CallDataEvent event) {
        // TODO: Implement tenant DB persistence logic
        // 1. Create InboundCallData entity from event
        // 2. Save to tenant database (routed via TenantContext)
        // 3. Extract and save patient data if present
        // 4. Save conversation transcript
        
        log.debug("💾 Saving to tenant DB: schemaName={}, callSid={}, duration={}s, cost=${}", 
                event.getSchemaName(), event.getCallSid(), event.getDuration(), event.getCost());
        
        // Example:
        // InboundCallData callData = InboundCallData.builder()
        //         .callSid(event.getCallSid())
        //         .fromNumber(event.getFromNumber())
        //         .toNumber(event.getToNumber())
        //         .direction(event.getDirection())
        //         .status(event.getStatus())
        //         .duration(event.getDuration())
        //         .cost(event.getCost())
        //         .transcript(event.getTranscript())
        //         .build();
        // 
        // inboundCallDataRepository.save(callData);
        
        // Simulate save
        log.info("✅ [SIMULATED] Call data saved to tenant DB schema: {}", event.getSchemaName());
    }
}
