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;
    private final com.saas.subscription.service.SubscriptionService subscriptionService;

    @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!");

                        // --- Subscription Usage Tracking ---
                        // Extract duration if available (Telnyx payload usually has 'duration_seconds'
                        // or similar)
                        // Assuming we can get duration from payload or it's calculated in
                        // fetchAndSaveCallCost
                        // For now, we'll try to get it from payload or default to 1 minute to be safe
                        Integer durationSeconds = null;
                        if (eventPayload.containsKey("duration_seconds")) {
                            Object durationObj = eventPayload.get("duration_seconds");
                            if (durationObj instanceof Number) {
                                durationSeconds = ((Number) durationObj).intValue();
                            }
                        }

                        if (durationSeconds != null) {
                            int durationMinutes = (int) Math.ceil(durationSeconds / 60.0);
                            // We need tenantId, not schemaName. identifyTenantSchema returns schemaName.
                            // We need to refactor identifyTenantSchema to return Tenant object or ID,
                            // or re-query. For efficiency, let's re-query or modify identifyTenantSchema
                            // later.
                            // For now, let's assume schemaName is close to tenantId or we can find it.
                            // Actually, identifyTenantSchema finds the tenant. Let's extract tenantId.

                            // Re-find tenant ID from phone number (since identifyTenantSchema returns
                            // schema)
                            Optional<PhoneNumber> phoneOpt = phoneNumberRepository.findByPhoneNumber(toNumber);
                            if (phoneOpt.isPresent()) {
                                String tenantId = phoneOpt.get().getTenantId();
                                boolean isOverage = subscriptionService.trackCallUsage(tenantId, durationMinutes);
                                if (isOverage) {
                                    log.warn("⚠️ [TelnyxCallEnd] Call was OVERAGE for tenant {}", tenantId);
                                    // TODO: Flag call record as overage (needs CallRecord entity update)
                                }
                            }
                        }
                        // -----------------------------------

                        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");
        }
    }
}
