package com.ease.gsms.server.services;

import com.ease.gsms.server.model.Device;
import com.ease.gsms.server.model.DeviceInfo;
import com.ease.gsms.server.model.Sim;
import com.ease.gsms.server.repositories.DeviceRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class DeviceService {

    @Autowired
    DeviceRepository deviceRepository;

    Map<String, DeviceInfo> onlineDevices = new ConcurrentHashMap<>();

    Set<DeviceUpdateObserver> observers = new HashSet<>();

    public boolean addObserver(DeviceUpdateObserver observer) {

        return observers.add(observer);

    }

    public boolean removeObserver(DeviceUpdateObserver observer) {

        return observers.remove(observer);

    }


    public DeviceInfo[] getUserDevices(String userName) {

        return deviceRepository.getUserDevices(userName);

    }

    public Device getDeviceBySimSerialNumber(String simSerialNumber) {

        return deviceRepository.getDeviceBySimSerialNumber(simSerialNumber);

    }

    public DeviceInfo getDeviceInfoByUuid(String uuid) {

        return deviceRepository.getDeviceInfoByUuid(uuid);

    }


    public void update(Device device, Sim[] sims) {

        deviceRepository.update(device, sims);

        if (device.getOnline()) {

            onlineDevices.put(device.getUuid(), new DeviceInfo(device, sims));

            observers.parallelStream().forEach(observer -> observer.updated(device, sims));

        } else {

            if (onlineDevices.remove(device.getUuid()) != null) {

                observers.parallelStream().forEach(observer -> observer.updated(device, sims));

            }

        }

    }

    public void offline(String deviceUuid) {

        DeviceInfo deviceInfo = onlineDevices.remove(deviceUuid);

        if (deviceInfo == null) {

            deviceInfo = new DeviceInfo(
                    deviceRepository.getDeviceByUuid(deviceUuid),
                    deviceRepository.getSimsByDeviceUuid(deviceUuid)
            );

        }


        deviceInfo.getDevice().setOnline(false);

        deviceRepository.update(deviceInfo.getDevice(), deviceInfo.getSims());

        DeviceInfo finalDeviceInfo = deviceInfo;

        observers.parallelStream().forEach(observer -> observer.updated(finalDeviceInfo.getDevice(), finalDeviceInfo.getSims()));

    }

    @Scheduled(fixedRate = 60000)
    protected void cleanup() {

        for (DeviceInfo deviceInfo : deviceRepository.getStaleOnlineDevice(new Date().getTime() - 130 * 1000)) {

            offline(deviceInfo.getDevice().getUuid());

        }

    }

}
