package com.psg.dlsysinfo.dl_sysinfo_server.service;

import com.psg.dlsysinfo.dl_sysinfo_server.dto.InstalledAppDTO;
import com.psg.dlsysinfo.dl_sysinfo_server.entity.Client;
import com.psg.dlsysinfo.dl_sysinfo_server.entity.Drive;
import com.psg.dlsysinfo.dl_sysinfo_server.entity.InstalledSoftware;
import com.psg.dlsysinfo.dl_sysinfo_server.entity.IpAddress;
import com.psg.dlsysinfo.dl_sysinfo_server.repository.*;
import com.psg.dlsysinfo.dl_sysinfo_server.security.EncryptionService;
import com.psg.dlsysinfo.dl_sysinfo_server.repository.InstalledSoftwareRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.psg.dlsysinfo.dl_sysinfo_server.entity.Devices;


import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

@Service
public class DemoDeviceGeneratorService {

    @Autowired
    private DevicesRepository devicesRepository;

    @Autowired
    private EncryptionService encryptionService;

    @Autowired
    private IpAddressRepository ipAddressRepository;

    @Autowired
    private CveRepository cveRepository;

    @Autowired
    private InstalledSoftwareRepository installedSoftwareRepository;

    @Autowired
    private VulnerabilityScannerService vulnScanner;
    @Autowired
    private DeviceService deviceService;

    private static final List<String> CPU_NAMES = List.of("Intel i7-12700K", "Ryzen 5 5600X", "Apple M1");
    private static final List<String> OS_VERSIONS = List.of("Windows 11 Pro", "Windows 10 Enterprise", "Ubuntu 22.04");
    private static final List<String> OS_NAMES = List.of("Windows", "Ubuntu", "macOS");
    private <T> T randomFrom(List<T> list) {
        return list.get((int) (Math.random() * list.size()));
    }

    private int randomInt(int min, int max) {
        return (int) (Math.random() * (max - min + 1)) + min;
    }



    // Add more preset data pools

    @Autowired private ClientRepository clientRepository;

    public Devices generateDemoDeviceForClient(Long clientId) {
        Client client = clientRepository.findById(clientId)
                .orElseThrow(() -> new IllegalArgumentException("Invalid client ID"));

        // Step 1: Decrypt the client name
        String decryptedName;
        try {
            decryptedName = encryptionService.decryptData(client.getClientNameEncrypted());
        } catch (Exception e) {
            throw new RuntimeException("Failed to decrypt client name", e);
        }

        // Step 2: Build client code from first 4 alphanumeric chars of name
        String clientCode = decryptedName
                .replaceAll("[^A-Za-z0-9]", "")
                .toUpperCase()
                .substring(0, Math.min(4, decryptedName.length()));

        // Step 3: Generate type and number
        String deviceType = Math.random() < 0.5 ? "SVR" : "WKS";
        String deviceNumber = String.format("%02d", randomInt(1, 99));

        // Step 4: Build final hostname
        String demoHost = String.format("DEMO-%s%s%s", clientCode, deviceType, deviceNumber);

        // Step 5: Hash and encrypt
        String hashedHostname = encryptionService.hashString(demoHost);

        // Step 6: Find or create device
        Devices device = devicesRepository.findByHashedHostname(hashedHostname).orElse(null);
        boolean isNew = false;

        if (device == null) {
            device = new Devices();
            device.setHashedHostname(hashedHostname);
            isNew = true;
        }

        device.setClient(client);
        device.setLastCheckedIn(LocalDateTime.now());

        try {
            device.setEncryptedHostname(encryptionService.encryptData(demoHost));
        } catch (Exception e) {
            throw new RuntimeException("Encryption failed", e);
        }

        // Random system info
        device.setOsName(randomFrom(OS_NAMES));
        device.setOsVersion(randomFrom(OS_VERSIONS));
        device.setWindowsVersion("22H2");
        device.setWindowsBuild("22631.3374");
        device.setOsArchitecture("x64");
        device.setProcessorName(randomFrom(CPU_NAMES));
        device.setProcessorArchitecture("x64");
        device.setGpuName("NVIDIA GeForce RTX 3060");

        int totalGB = randomInt(8, 64);
        device.setTotalMemory(String.valueOf(totalGB * 1024)); // in MB
        device.setLastBootTime(generateRandomBootTime());

        // Related tables
        device.setDrives(generateRandomDrives(device));
        device.setIpAddresses(generateRandomIps(device));
        device.setInstalledApplications(generateRandomSoftware(device));

        Devices saved = devicesRepository.save(device);
        System.out.println((isNew ? "🆕 Created" : "🔁 Updated") + " demo device with ID: " + saved.getDeviceId());

        return saved;
    }




    private List<Drive> generateRandomDrives(Devices device) {
        double totalC = randomDouble(256, 1024);
        double totalD = randomDouble(512, 2048);

        Drive cDrive = new Drive();
        cDrive.setName("C:");
        cDrive.setDriveType("NTFS");
        cDrive.setTotalSizeGB(roundToTwoDecimalPlaces(totalC));
        cDrive.setFreeSpaceGB(roundToTwoDecimalPlaces(totalC * 0.75));
        cDrive.setDevice(device);

        Drive dDrive = new Drive();
        dDrive.setName("D:");
        dDrive.setDriveType("NTFS");
        dDrive.setTotalSizeGB(roundToTwoDecimalPlaces(totalD));
        dDrive.setFreeSpaceGB(roundToTwoDecimalPlaces(totalD * 0.9));
        dDrive.setDevice(device);

        return List.of(cDrive, dDrive);
    }

    private double roundToTwoDecimalPlaces(double value) {
        return Math.round(value * 100.0) / 100.0;
    }
    private double randomDouble(int min, int max) {
        return min + (Math.random() * (max - min));
    }


    private String generateRandomBootTime() {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime randomBoot = now.minusDays(randomInt(0, 30)).withHour(randomInt(0, 23)).withMinute(randomInt(0, 59));
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return randomBoot.format(formatter);
    }




    private List<IpAddress> generateRandomIps(Devices device) {
        IpAddress ip1 = new IpAddress();
        ip1.setInterfaceName("Ethernet 0");
        ip1.setIpAddress("192.168.1." + randomInt(2, 254));
        ip1.setMacAddress(randomMac());
        ip1.setDevice(device);

        IpAddress ip2 = new IpAddress();
        ip2.setInterfaceName("Wi-Fi 1");
        ip2.setIpAddress("192.168.1." + randomInt(100, 200));
        ip2.setMacAddress(randomMac());
        ip2.setDevice(device);

        return List.of(ip1, ip2);
    }


    private String randomMac() {
        return "AA:BB:" + UUID.randomUUID().toString().substring(0, 2) + ":" +
               UUID.randomUUID().toString().substring(0, 2) + ":00:FF";
    }



    private List<InstalledSoftware> generateRandomSoftware(Devices device) {
        List<InstalledAppDTO> samples = installedSoftwareRepository.findDistinctInstalledAppDTOs();
        Collections.shuffle(samples);

        return samples.stream().limit(5).map(dto -> {
            InstalledSoftware software = new InstalledSoftware();
            software.setDevice(device);
            software.setAppName(dto.getApp_name());
            software.setAppVersion(dto.getApp_version());
            software.setPublisher(dto.getPublisher());

            software.setNormalizedAppName(null);
            software.setNormalizedProduct(null);
            software.setNormalizedPublisher(null);
            software.setLastUpdated(LocalDateTime.now());

            return software;
        }).toList();
    }




}

