package ru.kirillius.pf.sdn.service;

import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.springframework.stereotype.Service;
import ru.kirillius.pf.sdn.entity.DomainCacheEntry;
import ru.kirillius.pf.sdn.repository.DomainCacheRepository;

import java.net.Inet4Address;
import java.time.Duration;
import java.time.Instant;
import java.util.List;

@Setter
@RequiredArgsConstructor
@Service
public class DomainCacheService {
    private final DomainCacheRepository repository;
    private static final int DOMAIN_TTL_HOURS = 12;

    public void update(String domain, List<Inet4Address> addresses) {
        var minDate = Instant.now().minus(Duration.ofHours(DOMAIN_TTL_HOURS));
        synchronized (repository) {
            var existing = repository.getAllByDomain(domain);
            var existingAddresses = existing.stream().map(DomainCacheEntry::getAddress).toList();
            existing.forEach(entry -> {
                if (addresses.contains(entry.getAddress())) {
                    entry.setLastUpdate(Instant.now());
                    entry.setLastSeen(Instant.now());
                } else {
                    if (entry.getLastSeen().isBefore(minDate)) {
                        repository.delete(entry);
                    } else {
                        entry.setLastUpdate(Instant.now());
                    }
                }
            });

            addresses.stream()
                    .filter(address -> !existingAddresses.contains(address))
                    .forEach(address -> repository.save(
                                    DomainCacheEntry.builder()
                                            .domain(domain)
                                            .address(address)
                                            .lastUpdate(Instant.now())
                                            .lastSeen(Instant.now())
                                            .build()
                            )
                    );
        }
    }

    public List<Inet4Address> load(String domain, boolean filterOutdated) {
        var minDate = Instant.now().minus(Duration.ofHours(DOMAIN_TTL_HOURS));
        synchronized (repository) {
            var found = repository.getAllByDomain(domain);
            if (filterOutdated && !found.isEmpty()) {
                found = found.stream().filter(entry -> entry.getLastSeen().isAfter(minDate)).toList();
            }
            return found.stream().map(DomainCacheEntry::getAddress).toList();
        }
    }
}
