package com.psg.dlsysinfo.dl_sysinfo_server.controller;

import com.psg.dlsysinfo.dl_sysinfo_server.dto.DetailedDeviceDTO;
import com.psg.dlsysinfo.dl_sysinfo_server.dto.DeviceDTO;
import com.psg.dlsysinfo.dl_sysinfo_server.dto.DeviceVulnerabilityDTO;
import com.psg.dlsysinfo.dl_sysinfo_server.dto.DeviceWithCveResponse;
import com.psg.dlsysinfo.dl_sysinfo_server.repository.ClientRepository;
import com.psg.dlsysinfo.dl_sysinfo_server.repository.DevicesRepository;
import com.psg.dlsysinfo.dl_sysinfo_server.security.CurrentUser;
import com.psg.dlsysinfo.dl_sysinfo_server.service.DeviceService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/user/devices")
@RequiredArgsConstructor
public class UserDeviceController {

    private final DeviceService deviceService;
    private final ClientRepository clientRepository;
    private final DevicesRepository devicesRepository;

    @PreAuthorize("isAuthenticated()")
    @GetMapping
    public ResponseEntity<List<DeviceDTO>> getDevicesForAuthenticatedClient(@AuthenticationPrincipal CurrentUser user) {
        var client = clientRepository.findByClientIdentifier(user.getClientIdentifier())
                .orElseThrow(() -> new RuntimeException("Client not found"));

        List<DeviceDTO> devices = deviceService.getDevicesForClient(client.getClientId());
        return ResponseEntity.ok(devices);
    }

    @PreAuthorize("isAuthenticated()")
    @GetMapping("/{deviceId}")
    public ResponseEntity<DetailedDeviceDTO> getDeviceDetailsForClient(
            @PathVariable Long deviceId,
            @AuthenticationPrincipal CurrentUser user) {

        var client = clientRepository.findByClientIdentifier(user.getClientIdentifier())
                .orElseThrow(() -> new RuntimeException("Client not found"));

        var device = devicesRepository.findById(deviceId)
                .orElseThrow(() -> new RuntimeException("Device not found"));

        if (!device.getClient().getClientId().equals(client.getClientId())) {
            throw new RuntimeException("Unauthorized access to device.");
        }

        var detailedDevice = deviceService.getDeviceDetails(deviceId);
        return ResponseEntity.ok(detailedDevice);
    }

    @PreAuthorize("isAuthenticated()")
    @GetMapping("/with-vulns")
    public ResponseEntity<DeviceWithCveResponse> getDevicesWithVulnerabilities(@AuthenticationPrincipal CurrentUser user) {
        var client = clientRepository.findByClientIdentifier(user.getClientIdentifier())
                .orElseThrow(() -> new RuntimeException("Client not found"));

        List<DeviceDTO> devices = deviceService.getDevicesForClient(client.getClientId());

        Map<Long, List<DeviceVulnerabilityDTO>> vulnMap = deviceService
                .getVulnerabilitiesGroupedByDevice(client.getClientId())
                .entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> entry.getValue().stream()
                                .map(v -> new DeviceVulnerabilityDTO(
                                        v.getCveId(),                      // ✅ correct method name
                                        v.getDescription(),                // ✅
                                        v.getSeverity(),                   // ✅
                                        v.getScore(),                      // ✅ instead of getCvssScore()
                                        null,                              // ❗ Published date: not available in CveMatchResult, so set null
                                        v.getLastModifiedDate() != null ? v.getLastModifiedDate().toString() : null  // ✅ lastModifiedDate
                                ))
                                .toList()
                ));

        return ResponseEntity.ok(new DeviceWithCveResponse(devices, vulnMap));
    }
}