package com.airlock.iam.login.application.service.maintenancemessage;

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.common.api.domain.model.user.CurrentLocale;
import com.airlock.iam.common.domain.model.locale.LocalePreferences;
import com.airlock.iam.core.misc.sysmessage.MaintenanceMessage;
import com.airlock.iam.core.misc.sysmessage.MaintenanceMessageException;
import com.airlock.iam.core.misc.sysmessage.MaintenanceMessageService;
import com.airlock.iam.login.domain.model.maintenancemessage.CurrentMaintenanceMessage;
import com.airlock.iam.login.misc.plugin.MaintenanceMessageConfig;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.inject.Inject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class LoginMaintenanceMessageService {
   private final MaintenanceMessageService mmService;
   private final List<String> mmLocations;
   private final LocalePreferences localePreferences;
   private final CurrentLocale currentLocale;

   @Inject
   public LoginMaintenanceMessageService(MaintenanceMessageConfig config, LocalePreferences localePreferences, CurrentLocale currentLocale) {
      this.mmService = config.getMessageService();
      this.mmLocations = config.getLocations();
      if (this.mmLocations.size() > 1) {
         this.mmLocations.remove(null);
      }

      this.localePreferences = localePreferences;
      this.currentLocale = currentLocale;
   }

   public List<CurrentMaintenanceMessage> retrieveMaintenanceMessages(List<LoginMaintenanceMessageService.LocationFilter> locationFilters) {
      List<String> filteredLocations = this.filterLocations(locationFilters);
      List<CurrentMaintenanceMessage> result = new ArrayList<>();

      for (String location : filteredLocations) {
         try {
            MaintenanceMessage message = this.mmService.getMaintenanceMessage(new Date(), location);
            if (message != null) {
               result.add(this.convertFromPersistentBean(message));
            }
         } catch (MaintenanceMessageException e) {
            throw new FailureException(e);
         }
      }

      return result;
   }

   private List<String> filterLocations(List<LoginMaintenanceMessageService.LocationFilter> locationFilters) {
      return this.mmLocations
         .stream()
         .filter(location -> locationFilters.isEmpty() || locationFilters.stream().allMatch(filter -> this.matchOrFilter(location, filter)))
         .collect(Collectors.toList());
   }

   private boolean matchOrFilter(String location, LoginMaintenanceMessageService.LocationFilter locationFilter) {
      return location != null
         && (
            locationFilter.getContainedInLocation().stream().anyMatch(location::contains)
               || locationFilter.getEqualToLocation().stream().anyMatch(location::equals)
         );
   }

   private CurrentMaintenanceMessage convertFromPersistentBean(MaintenanceMessage message) {
      String defaultLanguage = this.localePreferences.getDefaultLocale().getLanguage();
      Optional<String> language = Optional.empty();
      Optional<String> text = Optional.empty();
      if (message.getLanguages().contains(this.currentLocale.getLanguage())) {
         language = Optional.of(this.currentLocale.getLanguage());
         text = Optional.of(message.getMessage(this.currentLocale.getLanguage()));
      } else if (message.getLanguages().contains(defaultLanguage)) {
         language = Optional.of(defaultLanguage);
         text = Optional.of(message.getMessage(defaultLanguage));
      }

      return CurrentMaintenanceMessage.builder()
         .id(message.getName())
         .systemAvailable(message.isSystemAvailable())
         .location(Optional.ofNullable(message.getLocation()))
         .language(language)
         .text(text)
         .validFrom(message.getValidFrom())
         .validTo(message.getValidTo())
         .build();
   }

   @SuppressFBWarnings(justification = "generated code")
   public static LoginMaintenanceMessageService.LoginMaintenanceMessageServiceBuilder builder() {
      return new LoginMaintenanceMessageService.LoginMaintenanceMessageServiceBuilder();
   }

   public static class LocationFilter {
      private List<String> containedInLocation;
      private List<String> equalToLocation;

      @SuppressFBWarnings(justification = "generated code")
      LocationFilter(List<String> containedInLocation, List<String> equalToLocation) {
         this.containedInLocation = containedInLocation;
         this.equalToLocation = equalToLocation;
      }

      @SuppressFBWarnings(justification = "generated code")
      public static LoginMaintenanceMessageService.LocationFilter.LocationFilterBuilder builder() {
         return new LoginMaintenanceMessageService.LocationFilter.LocationFilterBuilder();
      }

      @SuppressFBWarnings(justification = "generated code")
      public List<String> getContainedInLocation() {
         return this.containedInLocation;
      }

      @SuppressFBWarnings(justification = "generated code")
      public List<String> getEqualToLocation() {
         return this.equalToLocation;
      }

      @SuppressFBWarnings(justification = "generated code")
      public void setContainedInLocation(List<String> containedInLocation) {
         this.containedInLocation = containedInLocation;
      }

      @SuppressFBWarnings(justification = "generated code")
      public void setEqualToLocation(List<String> equalToLocation) {
         this.equalToLocation = equalToLocation;
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public boolean equals(Object o) {
         if (o == this) {
            return true;
         } else if (!(o instanceof LoginMaintenanceMessageService.LocationFilter other)) {
            return false;
         } else if (!other.canEqual(this)) {
            return false;
         } else {
            Object this$containedInLocation = this.containedInLocation;
            Object other$containedInLocation = other.containedInLocation;
            if (this$containedInLocation == null ? other$containedInLocation == null : this$containedInLocation.equals(other$containedInLocation)) {
               Object this$equalToLocation = this.equalToLocation;
               Object other$equalToLocation = other.equalToLocation;
               return this$equalToLocation == null ? other$equalToLocation == null : this$equalToLocation.equals(other$equalToLocation);
            } else {
               return false;
            }
         }
      }

      @SuppressFBWarnings(justification = "generated code")
      protected boolean canEqual(Object other) {
         return other instanceof LoginMaintenanceMessageService.LocationFilter;
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public int hashCode() {
         int PRIME = 59;
         int result = 1;
         Object $containedInLocation = this.containedInLocation;
         result = result * 59 + ($containedInLocation == null ? 43 : $containedInLocation.hashCode());
         Object $equalToLocation = this.equalToLocation;
         return result * 59 + ($equalToLocation == null ? 43 : $equalToLocation.hashCode());
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "LoginMaintenanceMessageService.LocationFilter(containedInLocation="
            + this.getContainedInLocation()
            + ", equalToLocation="
            + this.getEqualToLocation()
            + ")";
      }

      @SuppressFBWarnings(justification = "generated code")
      public static class LocationFilterBuilder {
         @SuppressFBWarnings(justification = "generated code")
         private ArrayList<String> containedInLocation;
         @SuppressFBWarnings(justification = "generated code")
         private ArrayList<String> equalToLocation;

         @SuppressFBWarnings(justification = "generated code")
         LocationFilterBuilder() {
         }

         @SuppressFBWarnings(justification = "generated code")
         public LoginMaintenanceMessageService.LocationFilter.LocationFilterBuilder locationContains(String locationContains) {
            if (this.containedInLocation == null) {
               this.containedInLocation = new ArrayList<>();
            }

            this.containedInLocation.add(locationContains);
            return this;
         }

         @SuppressFBWarnings(justification = "generated code")
         public LoginMaintenanceMessageService.LocationFilter.LocationFilterBuilder containedInLocation(Collection<? extends String> containedInLocation) {
            if (containedInLocation == null) {
               throw new NullPointerException("containedInLocation cannot be null");
            }

            if (this.containedInLocation == null) {
               this.containedInLocation = new ArrayList<>();
            }

            this.containedInLocation.addAll(containedInLocation);
            return this;
         }

         @SuppressFBWarnings(justification = "generated code")
         public LoginMaintenanceMessageService.LocationFilter.LocationFilterBuilder clearContainedInLocation() {
            if (this.containedInLocation != null) {
               this.containedInLocation.clear();
            }

            return this;
         }

         @SuppressFBWarnings(justification = "generated code")
         public LoginMaintenanceMessageService.LocationFilter.LocationFilterBuilder locationEquals(String locationEquals) {
            if (this.equalToLocation == null) {
               this.equalToLocation = new ArrayList<>();
            }

            this.equalToLocation.add(locationEquals);
            return this;
         }

         @SuppressFBWarnings(justification = "generated code")
         public LoginMaintenanceMessageService.LocationFilter.LocationFilterBuilder equalToLocation(Collection<? extends String> equalToLocation) {
            if (equalToLocation == null) {
               throw new NullPointerException("equalToLocation cannot be null");
            }

            if (this.equalToLocation == null) {
               this.equalToLocation = new ArrayList<>();
            }

            this.equalToLocation.addAll(equalToLocation);
            return this;
         }

         @SuppressFBWarnings(justification = "generated code")
         public LoginMaintenanceMessageService.LocationFilter.LocationFilterBuilder clearEqualToLocation() {
            if (this.equalToLocation != null) {
               this.equalToLocation.clear();
            }

            return this;
         }

         @SuppressFBWarnings(justification = "generated code")
         public LoginMaintenanceMessageService.LocationFilter build() {
            List containedInLocation = switch (this.containedInLocation == null ? 0 : this.containedInLocation.size()) {
               case 0 -> Collections.emptyList();
               case 1 -> Collections.singletonList(this.containedInLocation.get(0));
               default -> Collections.unmodifiableList(new ArrayList<>(this.containedInLocation));
            };

            return new LoginMaintenanceMessageService.LocationFilter(
               containedInLocation, switch (this.equalToLocation == null ? 0 : this.equalToLocation.size()) {
                  case 0 -> Collections.emptyList();
                  case 1 -> Collections.singletonList(this.equalToLocation.get(0));
                  default -> Collections.unmodifiableList(new ArrayList<>(this.equalToLocation));
               }
            );
         }

         @SuppressFBWarnings(justification = "generated code")
         @Override
         public String toString() {
            return "LoginMaintenanceMessageService.LocationFilter.LocationFilterBuilder(containedInLocation="
               + this.containedInLocation
               + ", equalToLocation="
               + this.equalToLocation
               + ")";
         }
      }
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class LoginMaintenanceMessageServiceBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private MaintenanceMessageConfig config;
      @SuppressFBWarnings(justification = "generated code")
      private LocalePreferences localePreferences;
      @SuppressFBWarnings(justification = "generated code")
      private CurrentLocale currentLocale;

      @SuppressFBWarnings(justification = "generated code")
      LoginMaintenanceMessageServiceBuilder() {
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginMaintenanceMessageService.LoginMaintenanceMessageServiceBuilder config(MaintenanceMessageConfig config) {
         this.config = config;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginMaintenanceMessageService.LoginMaintenanceMessageServiceBuilder localePreferences(LocalePreferences localePreferences) {
         this.localePreferences = localePreferences;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginMaintenanceMessageService.LoginMaintenanceMessageServiceBuilder currentLocale(CurrentLocale currentLocale) {
         this.currentLocale = currentLocale;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginMaintenanceMessageService build() {
         return new LoginMaintenanceMessageService(this.config, this.localePreferences, this.currentLocale);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "LoginMaintenanceMessageService.LoginMaintenanceMessageServiceBuilder(config="
            + this.config
            + ", localePreferences="
            + this.localePreferences
            + ", currentLocale="
            + this.currentLocale
            + ")";
      }
   }
}
