package com.airlock.iam.login.app.infrastructure.web;

import com.airlock.iam.base.domain.service.uri.IamUriBuilder;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.Strings;

public class SpaCustomTitle {
   static final String SPA_CUSTOM_TITLE_RELOAD_CONTEXT_ATTRIBUTE = "SPA_CUSTOM_TITLE_RELOAD";
   private static final ELogger LOG = ELoggerFactory.getLogger(SpaCustomTitle.class);
   private static final String DEFAULT_PATH_TO_CUSTOM_TITLE_PROPERTIES = concatPath(Strings.CS.removeStart("/ui", "/"), "assets/custom/title.properties");
   private static final String DEFAULT_TITLE = "&#65279;";
   private final Map<String, String> titleIdentifierToCustomTitle = new ConcurrentHashMap<>();

   public String getTitle(HttpServletRequest request) {
      this.reloadCustomTitles(request);
      Optional<String> optionalResourceSetName = getUiResourceSetName(request);
      String resourceSetName = optionalResourceSetName.orElse("default");
      return this.titleIdentifierToCustomTitle.computeIfAbsent(resourceSetName, k -> retrieveCustomTitle(optionalResourceSetName, request));
   }

   private void reloadCustomTitles(HttpServletRequest request) {
      ServletContext servletContext = request.getServletContext();
      Optional<Object> spaCustomTitlesReloadFlag = Optional.ofNullable(servletContext.getAttribute("SPA_CUSTOM_TITLE_RELOAD"));
      servletContext.removeAttribute("SPA_CUSTOM_TITLE_RELOAD");
      spaCustomTitlesReloadFlag.ifPresent(flag -> this.titleIdentifierToCustomTitle.clear());
   }

   private static Optional<String> getUiResourceSetName(HttpServletRequest request) {
      return Optional.ofNullable(request.getAttribute("uiResourceSetName")).filter(String.class::isInstance).map(String.class::cast);
   }

   private static String retrieveCustomTitle(Optional<String> uiResourceSetName, HttpServletRequest request) {
      return uiResourceSetName.<String>flatMap(resourceSetName -> loadCustomTitleForResourceSet(resourceSetName, request)).or(() -> {
         if (uiResourceSetName.isPresent()) {
            LOG.debug(String.format("Reverting to fallback title at '%s' ", DEFAULT_PATH_TO_CUSTOM_TITLE_PROPERTIES));
         }

         return loadCustomTitle(request, DEFAULT_PATH_TO_CUSTOM_TITLE_PROPERTIES);
      }).orElseGet(() -> {
         LOG.debug(String.format("Reverting to fallback title at '%s' ", "&#65279;"));
         return "&#65279;";
      });
   }

   private static Optional<String> loadCustomTitleForResourceSet(String uiResourceSetName, HttpServletRequest request) {
      String pathToUiResourceSetCustomTitlesProperties = IamUriBuilder.fromPath(Strings.CS.removeStart("/ui", "/"))
         .path(uiResourceSetName)
         .path("/assets/custom/title.properties")
         .build()
         .getPath();
      return loadCustomTitle(request, pathToUiResourceSetCustomTitlesProperties);
   }

   private static Optional<String> loadCustomTitle(HttpServletRequest request, String pathToTitleProperties) {
      try (InputStream titlePropertiesFile = request.getServletContext().getResourceAsStream(pathToTitleProperties)) {
         if (titlePropertiesFile == null) {
            LOG.debug(String.format("title.properties at '%s' does not exist.", pathToTitleProperties));
            return Optional.empty();
         } else {
            Reader reader = new InputStreamReader(titlePropertiesFile, StandardCharsets.UTF_8);
            Properties titleProperties = loadProperties(reader);
            if (!titleProperties.containsKey("title")) {
               LOG.debug(String.format("title.properties at '%s' is missing 'title' property.", pathToTitleProperties));
               return Optional.empty();
            } else {
               return Optional.of(titleProperties.getProperty("title"));
            }
         }
      } catch (IOException e) {
         LOG.debug(String.format("title.properties at '%s' does not exist.", pathToTitleProperties));
         return Optional.empty();
      }
   }

   private static Properties loadProperties(Reader resource) {
      Properties properties = new Properties();

      try {
         properties.load(resource);
      } catch (IOException e) {
         LOG.debug("Something went wrong closing the stream.");
      }

      return properties;
   }

   private static String concatPath(String uiResourceSetName, String path) {
      return IamUriBuilder.fromPath(uiResourceSetName).path(path).build().getPath();
   }
}
