package com.saas.shared.service;

import com.saas.shared.core.TenantContext;
import com.saas.tenant.entity.InboundCallData;
import com.saas.tenant.repository.InboundCallDataRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * Service for saving call data to BOTH admin database and tenant database
 * This enables:
 * 1. Tenant isolation (tenant database)
 * 2. Cross-tenant reporting (admin database)
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class DualSaveCallDataService {

    private final InboundCallDataRepository callDataRepository;

    /**
     * Save call data to BOTH databases:
     * 1. Admin database (saas_db) for cross-tenant reporting
     * 2. Tenant database for tenant isolation
     */
    public void saveToBothDatabases(InboundCallData callData, String tenantSchema) {
        log.info("🚀 [DualSaveCallDataService] saveToBothDatabases() CALLED");
        log.info("🚀 [DualSaveCallDataService] CallSid: {}, Provider: {}, TenantSchema: {}", 
            callData.getCallSid(), callData.getProvider(), tenantSchema);
        
        // Save to admin database (saas_db) for reporting
        saveToAdminDatabase(callData);
        
        // Save to tenant database for isolation
        saveToTenantDatabase(callData, tenantSchema);
        
        log.info("✅ [DualSaveCallDataService] Dual save completed for CallSid: {}", callData.getCallSid());
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    protected void saveToAdminDatabase(InboundCallData callData) {
        log.info("💾 [DualSaveCallDataService] saveToAdminDatabase() START - CallSid: {}", callData.getCallSid());
        
        try {
            log.info("🎯 [DualSaveCallDataService] Setting TenantContext to 'saas_db'");
            TenantContext.setTenantId("saas_db");
            
            // Clone to avoid ID conflicts
            InboundCallData adminCopy = cloneCallData(callData);
            log.info("📋 [DualSaveCallDataService] Cloned call data - CallSid: {}, Provider: {}", 
                adminCopy.getCallSid(), adminCopy.getProvider());
            
            log.info("💾 [DualSaveCallDataService] Calling repository.save() for ADMIN database...");
            InboundCallData saved = callDataRepository.save(adminCopy);
            
            log.info("✅ [DualSaveCallDataService] Call data saved to ADMIN database (saas_db)!");
            log.info("✅ [DualSaveCallDataService] Saved ID: {}, CallSid: {}, Provider: {}", 
                saved.getId(), saved.getCallSid(), saved.getProvider());
        } catch (Exception e) {
            log.error("❌ [DualSaveCallDataService] EXCEPTION saving to ADMIN database!", e);
            log.error("❌ [DualSaveCallDataService] Exception type: {}, Message: {}", 
                e.getClass().getName(), e.getMessage());
            log.error("❌ [DualSaveCallDataService] CallSid: {}", callData.getCallSid());
        } finally {
            TenantContext.clear();
            log.info("🧹 [DualSaveCallDataService] TenantContext cleared after ADMIN save");
        }
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    protected void saveToTenantDatabase(InboundCallData callData, String tenantSchema) {
        log.info("💾 [DualSaveCallDataService] saveToTenantDatabase() START - CallSid: {}, Schema: {}", 
            callData.getCallSid(), tenantSchema);
        
        try {
            log.info("🎯 [DualSaveCallDataService] Setting TenantContext to '{}'", tenantSchema);
            TenantContext.setTenantId(tenantSchema);
            
            log.info("📝 [DualSaveCallDataService] Call data details - Provider: {}, From: {}, To: {}", 
                callData.getProvider(), callData.getFromNumber(), callData.getToNumber());
            
            log.info("💾 [DualSaveCallDataService] Calling repository.save() for TENANT database...");
            InboundCallData saved = callDataRepository.save(callData);
            
            log.info("✅ [DualSaveCallDataService] Call data saved to TENANT database ({})!", tenantSchema);
            log.info("✅ [DualSaveCallDataService] Saved ID: {}, CallSid: {}, Provider: {}", 
                saved.getId(), saved.getCallSid(), saved.getProvider());
        } catch (Exception e) {
            log.error("❌ [DualSaveCallDataService] EXCEPTION saving to TENANT database '{}'!", tenantSchema, e);
            log.error("❌ [DualSaveCallDataService] Exception type: {}, Message: {}", 
                e.getClass().getName(), e.getMessage());
            log.error("❌ [DualSaveCallDataService] CallSid: {}", callData.getCallSid());
            log.error("❌ [DualSaveCallDataService] FULL STACK TRACE:", e);
        } finally {
            TenantContext.clear();
            log.info("🧹 [DualSaveCallDataService] TenantContext cleared after TENANT save");
        }
    }
    
    private InboundCallData cloneCallData(InboundCallData source) {
        return InboundCallData.builder()
                .callSid(source.getCallSid())
                .provider(source.getProvider())
                .fromNumber(source.getFromNumber())
                .toNumber(source.getToNumber())
                .direction(source.getDirection())
                .callStatus(source.getCallStatus())
                .startTime(source.getStartTime())
                .endTime(source.getEndTime())
                .duration(source.getDuration())
                .fromCity(source.getFromCity())
                .fromState(source.getFromState())
                .fromZip(source.getFromZip())
                .fromCountry(source.getFromCountry())
                .toCity(source.getToCity())
                .toState(source.getToState())
                .toZip(source.getToZip())
                .toCountry(source.getToCountry())
                .accountSid(source.getAccountSid())
                .apiVersion(source.getApiVersion())
                .called(source.getCalled())
                .caller(source.getCaller())
                .calledCity(source.getCalledCity())
                .calledCountry(source.getCalledCountry())
                .calledState(source.getCalledState())
                .calledZip(source.getCalledZip())
                .callerCity(source.getCallerCity())
                .callerCountry(source.getCallerCountry())
                .callerState(source.getCallerState())
                .callerZip(source.getCallerZip())
                .callToken(source.getCallToken())
                .forwardedFrom(source.getForwardedFrom())
                .parentCallSid(source.getParentCallSid())
                .recordingSid(source.getRecordingSid())
                .recordingUrl(source.getRecordingUrl())
                .stirVerstat(source.getStirVerstat())
                .build();
    }
}
