package com.psg.dlsysinfo.dl_sysinfo_server.service;

import com.psg.dlsysinfo.dl_sysinfo_server.dto.ComplianceSummaryDTO;
import com.psg.dlsysinfo.dl_sysinfo_server.dto.TopVulnerabilityDTO;
import com.psg.dlsysinfo.dl_sysinfo_server.dto.VulnerableSoftwareDTO;
import com.psg.dlsysinfo.dl_sysinfo_server.repository.ReportingRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class ReportingService {

    private final ReportingRepository reportingRepository;

    /**
     * Get compliance summary with high-level security metrics
     * Cached for 15 minutes due to high computation cost
     */
    @Cacheable(value = "complianceSummary", key = "#clientId")
    @Transactional(readOnly = true)
    public ComplianceSummaryDTO getComplianceSummary(Long clientId) {
        log.info("Generating compliance summary for client: {}", clientId);

        Long totalDevices = reportingRepository.countTotalDevices(clientId);
        Long vulnerableDevices = reportingRepository.countVulnerableDevices(clientId);
        Long totalVulnerabilities = reportingRepository.countTotalVulnerabilities(clientId);
        Long criticalVulns = reportingRepository.countCriticalVulnerabilities(clientId);
        Long highVulns = reportingRepository.countHighVulnerabilities(clientId);
        Long mediumVulns = reportingRepository.countMediumVulnerabilities(clientId);
        Long lowVulns = reportingRepository.countLowVulnerabilities(clientId);
        Long totalSoftware = reportingRepository.countTotalSoftware(clientId);
        Long vulnerableSoftware = reportingRepository.countVulnerableSoftware(clientId);
        LocalDateTime lastUpdated = reportingRepository.findLastVulnerabilityScanDate(clientId);

        return ComplianceSummaryDTO.builder()
                .totalDevices(totalDevices != null ? totalDevices : 0L)
                .vulnerableDevices(vulnerableDevices != null ? vulnerableDevices : 0L)
                .totalVulnerabilities(totalVulnerabilities != null ? totalVulnerabilities : 0L)
                .criticalVulns(criticalVulns != null ? criticalVulns : 0L)
                .highVulns(highVulns != null ? highVulns : 0L)
                .mediumVulns(mediumVulns != null ? mediumVulns : 0L)
                .lowVulns(lowVulns != null ? lowVulns : 0L)
                .totalSoftware(totalSoftware != null ? totalSoftware : 0L)
                .vulnerableSoftware(vulnerableSoftware != null ? vulnerableSoftware : 0L)
                .lastUpdated(lastUpdated != null ? lastUpdated : LocalDateTime.now())
                .build();
    }

    /**
     * Get top vulnerabilities by severity and affected device count
     * Cached for 30 minutes due to moderate update frequency
     */
    @Cacheable(value = "topVulnerabilities", key = "#clientId")
    @Transactional(readOnly = true)
    public List<TopVulnerabilityDTO> getTopVulnerabilities(Long clientId) {
        log.info("Fetching top vulnerabilities for client: {}", clientId);
        List<Object[]> results = reportingRepository.findTopVulnerabilitiesNative(clientId);

        return results.stream()
                .map(row -> TopVulnerabilityDTO.builder()
                        .cveId((String) row[0])
                        .title((String) row[1])
                        .severity((String) row[2])
                        .score(row[3] != null ? ((Number) row[3]).doubleValue() : null)
                        .affectedDevices(row[4] != null ? ((Number) row[4]).longValue() : 0L)
                        .build())
                .collect(Collectors.toList());
    }

    /**
     * Get vulnerable software packages by risk score
     * Cached for 1 hour due to less frequent changes
     */
    @Cacheable(value = "vulnerableSoftware", key = "#clientId")
    @Transactional(readOnly = true)
    public List<VulnerableSoftwareDTO> getVulnerableSoftware(Long clientId) {
        log.info("Fetching vulnerable software for client: {}", clientId);
        List<Object[]> results = reportingRepository.findVulnerableSoftwareNative(clientId);

        return results.stream()
                .map(row -> VulnerableSoftwareDTO.builder()
                        .softwareName((String) row[0])
                        .totalInstances(row[1] != null ? ((Number) row[1]).longValue() : 0L)
                        .vulnerableInstances(row[2] != null ? ((Number) row[2]).longValue() : 0L)
                        .totalCves(row[3] != null ? ((Number) row[3]).longValue() : 0L)
                        .build())
                .collect(Collectors.toList());
    }
}
