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.tenant.entity.InboundCallData;
import com.saas.tenant.service.InboundCallService;
import com.saas.voip.extractor.ZiwoCallDataExtractor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

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

@RestController
@RequestMapping("/api/voip/ziwo")
@RequiredArgsConstructor
@Slf4j
public class ZiwoVoiceController {

    private final PhoneNumberRepository phoneNumberRepository;
    private final TenantRepository tenantRepository;
    private final InboundCallService inboundCallService;
    private final ZiwoCallDataExtractor ziwoCallDataExtractor;

    @PostMapping("/incoming-call")
    public ResponseEntity<Map<String, Object>> handleIncomingCall(@RequestBody Map<String, Object> payload) {
        log.info("Received Ziwo incoming call webhook: {}", payload);

        try {
            String toNumber = payload.get("to") != null ? payload.get("to").toString() : null;
            
            if (toNumber == null || toNumber.isEmpty()) {
                log.warn("No 'to' number in Ziwo webhook");
                return ResponseEntity.badRequest().body(Map.of("error", "Missing 'to' number"));
            }

            TenantContext.clear();

            Optional<PhoneNumber> phoneOpt = phoneNumberRepository.findByPhoneNumber(toNumber);
            
            if (!phoneOpt.isPresent() || phoneOpt.get().getProvider() != Provider.ZIWO) {
                log.warn("No Ziwo phone number found for: {}", toNumber);
                return ResponseEntity.status(HttpStatus.NOT_FOUND)
                    .body(Map.of("error", "Phone number not configured"));
            }

            PhoneNumber phoneNumber = phoneOpt.get();
            String tenantId = phoneNumber.getTenantId();
            
            Optional<Tenant> tenantOpt = tenantRepository.findByTenantId(tenantId);
            if (!tenantOpt.isPresent()) {
                log.error("Tenant not found for phone number: {}", toNumber);
                return ResponseEntity.status(HttpStatus.NOT_FOUND)
                    .body(Map.of("error", "Tenant not found"));
            }

            Tenant tenant = tenantOpt.get();
            String schemaName = tenant.getSchemaName();
            
            TenantContext.setTenantId(schemaName);
            log.info("Set tenant context for Ziwo call: {}", schemaName);

            try {
                InboundCallData callData = ziwoCallDataExtractor.extractFromZiwoRequest(payload);
                inboundCallService.saveCallData(callData);
                log.info("Saved Ziwo inbound call data: {}", callData.getCallSid());

                Map<String, Object> response = new HashMap<>();
                response.put("status", "success");
                response.put("message", "Call received and logged");
                response.put("call_id", callData.getCallSid());

                return ResponseEntity.ok(response);
            } finally {
                TenantContext.clear();
            }

        } catch (Exception e) {
            log.error("Error handling Ziwo incoming call", e);
            TenantContext.clear();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(Map.of("error", "Internal server error"));
        }
    }

    @GetMapping("/health")
    public ResponseEntity<Map<String, Object>> health() {
        Map<String, Object> response = new HashMap<>();
        response.put("status", "UP");
        response.put("provider", "Ziwo");
        response.put("timestamp", System.currentTimeMillis());
        return ResponseEntity.ok(response);
    }
}
