package com.saas.admin.controller;

import com.saas.admin.entity.Tenant;
import com.saas.admin.repository.TenantRepository;
import com.saas.shared.core.TenantContext;
import com.saas.tenant.entity.CallCostRecord;
import com.saas.tenant.service.CallCostTrackingService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

@RestController
@RequestMapping("/api/admin/costs")
@RequiredArgsConstructor
@Slf4j
@PreAuthorize("hasRole('SYSTEM_ADMIN')")
public class AdminCostController {
    
    private final CallCostTrackingService callCostTrackingService;
    private final TenantRepository tenantRepository;
    
    @GetMapping("/tenant/{tenantId}")
    public ResponseEntity<Map<String, Object>> getTenantCosts(
            @PathVariable String tenantId,
            @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
            @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) {
        
        log.info("📊 Fetching costs for tenant: {} from {} to {}", tenantId, startDate, endDate);
        
        Optional<Tenant> tenantOpt = tenantRepository.findByTenantId(tenantId);
        
        if (tenantOpt.isEmpty()) {
            return ResponseEntity.notFound().build();
        }
        
        String schemaName = tenantOpt.get().getSchemaName();
        
        LocalDateTime start = startDate != null ? startDate.atStartOfDay() : LocalDate.now().withDayOfMonth(1).atStartOfDay();
        LocalDateTime end = endDate != null ? endDate.atTime(23, 59, 59) : LocalDateTime.now();
        
        TenantContext.setTenantId(schemaName);
        
        try {
            Map<String, Object> report = callCostTrackingService.getTenantCostReport(start, end);
            List<CallCostRecord> records = callCostTrackingService.getAllCostRecords(start, end);
            
            Map<String, Object> response = new HashMap<>();
            response.put("tenantId", tenantId);
            response.put("tenantName", tenantOpt.get().getTenantName());
            response.put("schemaName", schemaName);
            response.put("period", Map.of("start", start, "end", end));
            response.put("summary", report);
            response.put("records", records);
            
            return ResponseEntity.ok(response);
            
        } finally {
            TenantContext.clear();
        }
    }
    
    @GetMapping("/summary")
    public ResponseEntity<Map<String, Object>> getGlobalCostSummary(
            @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
            @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) {
        
        LocalDateTime start = startDate != null ? startDate.atStartOfDay() : LocalDate.now().withDayOfMonth(1).atStartOfDay();
        LocalDateTime end = endDate != null ? endDate.atTime(23, 59, 59) : LocalDateTime.now();
        
        log.info("📊 Fetching global cost summary from {} to {}", start, end);
        
        List<Tenant> tenants = tenantRepository.findAll();
        
        Map<String, Object> globalSummary = new HashMap<>();
        BigDecimal totalCost = BigDecimal.ZERO;
        Long totalCalls = 0L;
        Map<String, BigDecimal> costByProvider = new HashMap<>();
        List<Map<String, Object>> tenantSummaries = new ArrayList<>();
        
        for (Tenant tenant : tenants) {
            try {
                TenantContext.setTenantId(tenant.getSchemaName());
                
                Map<String, Object> tenantReport = callCostTrackingService.getTenantCostReport(start, end);
                
                BigDecimal tenantCost = (BigDecimal) tenantReport.getOrDefault("totalCost", BigDecimal.ZERO);
                Long tenantCalls = (Long) tenantReport.getOrDefault("totalCalls", 0L);
                Map<String, BigDecimal> tenantProviderCosts = 
                    (Map<String, BigDecimal>) tenantReport.getOrDefault("costByProvider", new HashMap<>());
                
                totalCost = totalCost.add(tenantCost);
                totalCalls += tenantCalls;
                
                for (Map.Entry<String, BigDecimal> entry : tenantProviderCosts.entrySet()) {
                    costByProvider.merge(entry.getKey(), entry.getValue(), BigDecimal::add);
                }
                
                Map<String, Object> tenantSummary = new HashMap<>();
                tenantSummary.put("tenantId", tenant.getTenantId());
                tenantSummary.put("tenantName", tenant.getTenantName());
                tenantSummary.put("totalCost", tenantCost);
                tenantSummary.put("totalCalls", tenantCalls);
                tenantSummary.put("costByProvider", tenantProviderCosts);
                
                tenantSummaries.add(tenantSummary);
                
            } catch (Exception e) {
                log.error("Error fetching costs for tenant: {}", tenant.getTenantId(), e);
            } finally {
                TenantContext.clear();
            }
        }
        
        globalSummary.put("period", Map.of("start", start, "end", end));
        globalSummary.put("totalCost", totalCost);
        globalSummary.put("totalCalls", totalCalls);
        globalSummary.put("costByProvider", costByProvider);
        globalSummary.put("tenantCount", tenants.size());
        globalSummary.put("tenants", tenantSummaries);
        
        log.info("💰 Global summary - Total cost: {} USD, Total calls: {}, Tenants: {}", 
                totalCost, totalCalls, tenants.size());
        
        return ResponseEntity.ok(globalSummary);
    }
    
    @GetMapping("/provider/{provider}")
    @PreAuthorize("hasRole('SYSTEM_ADMIN')")
    public ResponseEntity<Map<String, Object>> getCostsByProvider(
            @PathVariable String provider,
            @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
            @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) {
        
        LocalDateTime start = startDate != null ? startDate.atStartOfDay() : LocalDate.now().withDayOfMonth(1).atStartOfDay();
        LocalDateTime end = endDate != null ? endDate.atTime(23, 59, 59) : LocalDateTime.now();
        
        log.info("📊 Fetching costs for provider: {} from {} to {}", provider, start, end);
        
        List<Tenant> tenants = tenantRepository.findAll();
        
        List<CallCostRecord> allRecords = new ArrayList<>();
        BigDecimal totalCost = BigDecimal.ZERO;
        
        for (Tenant tenant : tenants) {
            try {
                TenantContext.setTenantId(tenant.getSchemaName());
                
                List<CallCostRecord> records = callCostTrackingService.getCostRecordsByProvider(provider.toUpperCase());
                
                for (CallCostRecord record : records) {
                    if (record.getCallStartTime() != null && 
                        !record.getCallStartTime().isBefore(start) && 
                        !record.getCallStartTime().isAfter(end)) {
                        allRecords.add(record);
                        if (record.getCost() != null) {
                            totalCost = totalCost.add(record.getCost());
                        }
                    }
                }
                
            } catch (Exception e) {
                log.error("Error fetching provider costs for tenant: {}", tenant.getTenantId(), e);
            } finally {
                TenantContext.clear();
            }
        }
        
        Map<String, Object> response = new HashMap<>();
        response.put("provider", provider.toUpperCase());
        response.put("period", Map.of("start", start, "end", end));
        response.put("totalCost", totalCost);
        response.put("totalCalls", allRecords.size());
        response.put("records", allRecords);
        
        return ResponseEntity.ok(response);
    }
}
