package com.iqser.red.service.persistence.management.v1.processor.service.persistence;

import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import jakarta.transaction.Transactional;

import org.springframework.beans.BeanUtils;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import com.iqser.red.service.persistence.management.v1.processor.entity.notification.NotificationPreferencesEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.NotificationPreferencesRepository;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.NotificationRepository;
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
import com.iqser.red.service.persistence.service.v1.api.shared.model.notification.NotificationPreferences;
import com.iqser.red.service.persistence.service.v1.api.shared.model.notification.NotificationType;

import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;

@Service
@RequiredArgsConstructor
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class NotificationPreferencesPersistenceService {

    NotificationPreferencesRepository notificationPreferencesRepository;

    NotificationRepository notificationRepository;


    @Transactional
    public void createNotificationPreferences(String userId) {

        var notificationPreference = new NotificationPreferencesEntity();
        notificationPreference.setUserId(userId);
        notificationPreference.setEmailNotificationsEnabled(false);
        notificationPreference.setInAppNotificationsEnabled(true);
        notificationPreference.setInAppNotifications(Arrays.stream(NotificationType.values())
                                                             .map(Enum::name)
                                                             .collect(Collectors.toList()));
        notificationPreferencesRepository.save(notificationPreference);
    }


    @Transactional
    public NotificationPreferences getByUserId(String userId) {

        var notificationPreferencesEntityOptional = notificationPreferencesRepository.findByUserId(userId);

        return notificationPreferencesEntityOptional.map(this::convertPreferences)
                .orElse(null);
    }


    @Transactional
    public void setNotificationPreference(String userId, NotificationPreferences newNotificationPreferences) {

        notificationPreferencesRepository.findById(userId).ifPresentOrElse(oldNotificationPreferences -> {

            // if we disabled the notification preferences just now
            if (oldNotificationPreferences.isInAppNotificationsEnabled() != newNotificationPreferences.isInAppNotificationsEnabled()) {
                notificationRepository.deleteAllByUserId(userId, OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
            }

            var removedNotificationTypes = new ArrayList<>(oldNotificationPreferences.getInAppNotifications());
            removedNotificationTypes.removeAll(newNotificationPreferences.getInAppNotifications());

            if (!removedNotificationTypes.isEmpty()) {
                notificationRepository.deleteAllByUserIdAndNotificationTypeIn(userId, removedNotificationTypes, OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
            }

            BeanUtils.copyProperties(newNotificationPreferences, oldNotificationPreferences);

        }, () -> {
            NotificationPreferencesEntity notificationPreferencesEntity = new NotificationPreferencesEntity();
            BeanUtils.copyProperties(newNotificationPreferences, notificationPreferencesEntity);
            notificationPreferencesEntity.setUserId(userId);
            notificationPreferencesRepository.save(notificationPreferencesEntity);
        });
    }


    @Transactional
    public void deleteNotificationPreferences(String userId) {

        notificationPreferencesRepository.deleteByUserId(userId);
    }


    public List<NotificationPreferencesEntity> findAll() {

        return notificationPreferencesRepository.findAll();
    }


    private NotificationPreferences convertPreferences(NotificationPreferencesEntity preferences) {

        var result = MagicConverter.convert(preferences, NotificationPreferences.class);
        result.setInAppNotifications(new ArrayList<>(preferences.getInAppNotifications()));
        result.setEmailNotifications(new ArrayList<>(preferences.getEmailNotifications()));
        return result;
    }

}
