package com.saas.voip.controller;

import com.saas.admin.entity.PhoneNumber;
import com.saas.admin.entity.Tenant;
import com.saas.admin.repository.PhoneNumberRepository;
import com.saas.admin.repository.TenantRepository;
import com.saas.shared.core.TenantContext;
import com.saas.shared.enums.Provider;
import com.saas.voip.service.TelnyxCostService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;
import java.util.Optional;

@RestController
@RequestMapping("/api/voip/telnyx")
@RequiredArgsConstructor
@Slf4j
public class TelnyxCallEndController {
    
    private final TelnyxCostService telnyxCostService;
    private final PhoneNumberRepository phoneNumberRepository;
    private final TenantRepository tenantRepository;
    
    @PostMapping("/call-ended")
    public ResponseEntity<Map<String, Object>> handleCallEnded(@RequestBody Map<String, Object> payload) {
        
        try {
            log.info("╔═══════════════════════════════════════════════════════╗");
            log.info("║     TELNYX CALL ENDED WEBHOOK RECEIVED               ║");
            log.info("╚═══════════════════════════════════════════════════════╝");
            log.info("📥 [TelnyxCallEnd] Raw payload received: {}", payload);
            
            // Extract nested data structure
            Map<String, Object> data = (Map<String, Object>) payload.get("data");
            if (data == null) {
                log.error("❌ [TelnyxCallEnd] No 'data' field in payload!");
                return ResponseEntity.ok(Map.of("status", "error", "reason", "missing_data"));
            }
            log.info("📦 [TelnyxCallEnd] Data field extracted: {}", data);
            
            Map<String, Object> eventPayload = (Map<String, Object>) data.get("payload");
            if (eventPayload == null) {
                log.error("❌ [TelnyxCallEnd] No 'payload' field in data!");
                return ResponseEntity.ok(Map.of("status", "error", "reason", "missing_payload"));
            }
            log.info("📦 [TelnyxCallEnd] Event payload extracted: {}", eventPayload);
            
            String eventType = (String) eventPayload.get("event_type");
            String callSessionId = (String) eventPayload.get("call_session_id");
            String fromNumber = (String) eventPayload.get("from");
            String toNumber = (String) eventPayload.get("to");
            String state = (String) eventPayload.get("state");
            
            log.info("🎯 [TelnyxCallEnd] Parsed event data:");
            log.info("   ├─ Event Type: {}", eventType);
            log.info("   ├─ Call Session ID: {}", callSessionId);
            log.info("   ├─ From: {}", fromNumber);
            log.info("   ├─ To: {}", toNumber);
            log.info("   └─ State: {}", state);
            
            if (callSessionId == null || callSessionId.isEmpty()) {
                log.error("❌ [TelnyxCallEnd] Missing call_session_id!");
                return ResponseEntity.ok(Map.of("status", "error", "reason", "missing_call_session_id"));
            }
            
            if ("call.hangup".equals(eventType)) {
                log.info("✅ [TelnyxCallEnd] Event type is 'call.hangup' - processing call cost...");
                
                log.info("🔍 [TelnyxCallEnd] Identifying tenant schema for number: {}", toNumber);
                String schemaName = identifyTenantSchema(toNumber);
                
                if (schemaName != null) {
                    log.info("✅ [TelnyxCallEnd] Tenant schema identified: {}", schemaName);
                    log.info("🚀 [TelnyxCallEnd] Calling TelnyxCostService.fetchAndSaveCallCost()...");
                    
                    try {
                        telnyxCostService.fetchAndSaveCallCost(callSessionId, fromNumber, toNumber, schemaName);
                        log.info("✅ [TelnyxCallEnd] Telnyx call cost retrieval initiated successfully!");
                        log.info("   ├─ Session ID: {}", callSessionId);
                        log.info("   ├─ Tenant Schema: {}", schemaName);
                        log.info("   └─ Status: Cost fetch in progress");
                    } catch (Exception costEx) {
                        log.error("❌ [TelnyxCallEnd] EXCEPTION while fetching call cost!", costEx);
                        log.error("❌ [TelnyxCallEnd] Exception type: {}", costEx.getClass().getName());
                        log.error("❌ [TelnyxCallEnd] Exception message: {}", costEx.getMessage());
                    }
                } else {
                    log.warn("⚠️ [TelnyxCallEnd] Could not identify tenant schema for number: {}", toNumber);
                    log.warn("⚠️ [TelnyxCallEnd] Possible reasons:");
                    log.warn("   ├─ Phone number not found in database");
                    log.warn("   ├─ Phone number not assigned to TELNYX provider");
                    log.warn("   └─ Tenant not found for phone number");
                }
            } else {
                log.info("⏭️ [TelnyxCallEnd] Event type is '{}' (not 'call.hangup') - skipping cost fetch", eventType);
            }
            
            log.info("✅ [TelnyxCallEnd] Webhook processed successfully");
            return ResponseEntity.ok(Map.of("status", "received"));
            
        } catch (Exception e) {
            log.error("╔═══════════════════════════════════════════════════════╗");
            log.error("║     CRITICAL ERROR IN TELNYX CALL END WEBHOOK        ║");
            log.error("╚═══════════════════════════════════════════════════════╝");
            log.error("❌ [TelnyxCallEnd] EXCEPTION in handleCallEnded()", e);
            log.error("❌ [TelnyxCallEnd] Exception type: {}", e.getClass().getName());
            log.error("❌ [TelnyxCallEnd] Exception message: {}", e.getMessage());
            log.error("❌ [TelnyxCallEnd] Stack trace:", e);
            return ResponseEntity.ok(Map.of("status", "error", "message", e.getMessage()));
        }
    }
    
    private String identifyTenantSchema(String phoneNumber) {
        log.info("🔎 [TelnyxCallEnd] identifyTenantSchema() - Looking up phone number: {}", phoneNumber);
        
        if (phoneNumber == null || phoneNumber.isEmpty()) {
            log.warn("⚠️ [TelnyxCallEnd] Phone number is null or empty!");
            return null;
        }
        
        try {
            log.info("🎯 [TelnyxCallEnd] Setting TenantContext to 'saas_db' for admin database query");
            TenantContext.setTenantId("saas_db");
            
            log.info("🔍 [TelnyxCallEnd] Querying phone_numbers table for: {}", phoneNumber);
            Optional<PhoneNumber> phoneOpt = phoneNumberRepository.findByPhoneNumber(phoneNumber);
            
            if (phoneOpt.isEmpty()) {
                log.warn("⚠️ [TelnyxCallEnd] Phone number NOT FOUND in database: {}", phoneNumber);
                return null;
            }
            
            PhoneNumber phone = phoneOpt.get();
            log.info("✅ [TelnyxCallEnd] Phone number found in database!");
            log.info("   ├─ Phone Number: {}", phone.getPhoneNumber());
            log.info("   ├─ Provider: {}", phone.getProvider());
            log.info("   ├─ Tenant ID: {}", phone.getTenantId());
            log.info("   └─ Active: {}", phone.getIsActive());
            
            if (phone.getProvider() != Provider.TELNYX) {
                log.warn("⚠️ [TelnyxCallEnd] Phone number provider is {} (not TELNYX) - skipping", phone.getProvider());
                return null;
            }
            
            String tenantId = phone.getTenantId();
            log.info("🔍 [TelnyxCallEnd] Querying tenants table for tenant ID: {}", tenantId);
            Optional<Tenant> tenantOpt = tenantRepository.findByTenantId(tenantId);
            
            if (tenantOpt.isEmpty()) {
                log.warn("⚠️ [TelnyxCallEnd] Tenant NOT FOUND for tenant ID: {}", tenantId);
                return null;
            }
            
            Tenant tenant = tenantOpt.get();
            String schemaName = tenant.getSchemaName();
            log.info("✅ [TelnyxCallEnd] Tenant found!");
            log.info("   ├─ Tenant ID: {}", tenant.getTenantId());
            log.info("   ├─ Tenant Name: {}", tenant.getTenantName());
            log.info("   └─ Schema Name: {}", schemaName);
            
            return schemaName;
            
        } catch (Exception e) {
            log.error("❌ [TelnyxCallEnd] EXCEPTION in identifyTenantSchema()", e);
            log.error("❌ [TelnyxCallEnd] Exception type: {}", e.getClass().getName());
            log.error("❌ [TelnyxCallEnd] Exception message: {}", e.getMessage());
            return null;
        } finally {
            TenantContext.clear();
            log.info("🧹 [TelnyxCallEnd] TenantContext cleared after schema lookup");
        }
    }
}
