package marketing.heyday.hartmann.fotodocumentation.core.utils;

import java.nio.charset.Charset;
import java.security.Principal;
import java.util.Optional;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wildfly.security.auth.principal.NamePrincipal;
import org.wildfly.security.auth.server.RealmUnavailableException;
import org.wildfly.security.auth.server.SecurityDomain;
import org.wildfly.security.auth.server.SecurityIdentity;
import org.wildfly.security.evidence.PasswordGuessEvidence;

import jakarta.servlet.http.HttpServletRequest;
import javaslang.Tuple;
import javaslang.Tuple2;

/**
 * 
 * <p>Copyright: Copyright (c) 2024</p>
 * <p>Company: heyday Marketing GmbH</p>
 * @author <a href="mailto:p.verboom@heyday.marketing">Patrick Verboom</a>
 * @version 1.0
 * 
 * created: 20 Jan 2026
 */

public class LoginUtils {
	private static final Log LOG = LogFactory.getLog(LoginUtils.class);
	private static final int BASIC_HEADER_SIZE = 6;
	private static final int USERPASS_LENGTH = 1;

	public Optional<SecurityIdentity> authenticate(HttpServletRequest httpServletRequest) {
		Tuple2<String, String> userPass = extractUsernamePassword(httpServletRequest);
		if (userPass._1.isBlank() || userPass._2.isBlank()) {
			return Optional.empty();
		}
		return authenticate(userPass._1, userPass._2);
	}

	private Optional<SecurityIdentity> authenticate(String username, String password) {
		try {
			LOG.debug("Login with username & password " + username);
			Principal principal = new NamePrincipal(username);
			PasswordGuessEvidence evidence = new PasswordGuessEvidence(password.toCharArray());

			SecurityDomain sd = SecurityDomain.getCurrent();
			SecurityIdentity identity = sd.authenticate(principal, evidence); 
			LOG.debug("Login identity: " + identity);
			return Optional.ofNullable(identity);
		} catch (RealmUnavailableException | SecurityException e) {
			LOG.warn("Failed to authenticate user " +  e.getMessage(), e);
			return Optional.empty();
		}
	}

	private Tuple2<String, String> extractUsernamePassword(HttpServletRequest httpServletRequest) {
		Optional<String[]> userPassOptional = extractAuthHeader(httpServletRequest);

		if (userPassOptional.isPresent() && userPassOptional.get().length >= USERPASS_LENGTH) {
			String[] userpass = userPassOptional.get();
			String username = userpass[0];
			String password = userpass.length > USERPASS_LENGTH ? userpass[1] : "";

			return Tuple.of(username, password);
		}
		return Tuple.of("", "");
	}

	private Optional<String[]> extractAuthHeader(HttpServletRequest httpServletRequest) {
		Optional<String[]> retVal = Optional.empty();

		String authorization = httpServletRequest.getHeader("Authorization");
		if (authorization != null && StringUtils.length(authorization) > BASIC_HEADER_SIZE) {
			authorization = authorization.substring(BASIC_HEADER_SIZE);
			String decoded = StringUtils.toEncodedString(Base64.decodeBase64(authorization), Charset.forName("utf-8"));
			retVal = Optional.of(decoded.split(":"));
		}
		return retVal;
	}

	/**
	 * Extract device information from User-Agent header
	 *
	 * @param request HTTP servlet request
	 * @return Device/browser information
	 */
	public String extractDeviceInfo(HttpServletRequest request) {
		String userAgent = request.getHeader("User-Agent");
		return userAgent != null ? userAgent : "Unknown";
	}

	/**
	 * Extract client IP address, considering proxies
	 *
	 * @param request HTTP servlet request
	 * @return Client IP address
	 */
	public String extractIpAddress(HttpServletRequest request) {
		String xForwardedFor = request.getHeader("X-Forwarded-For");
		if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
			// X-Forwarded-For can contain multiple IPs, take the first one
			return xForwardedFor.split(",")[0].trim();
		}
		return request.getRemoteAddr();
	}
}
