package org.gcube.application.geoportal.service.utils;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.gcube.application.geoportal.common.model.document.accounting.AccountingInfo;
import org.gcube.application.geoportal.common.model.document.accounting.Context;
import org.gcube.application.geoportal.common.model.document.accounting.User;
import org.gcube.common.authorization.library.provider.AccessTokenProvider;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.authorization.library.provider.ClientInfo;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.scope.api.ScopeProvider;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Slf4j
public class UserUtils {

	public static List<String> DEFAULT_ROLES=new ArrayList<>();

	public static AuthenticatedUser getCurrent() throws SecurityException {
		String context=ScopeProvider.instance.get();
		if(context==null) throw new SecurityException("Cannot determine context");

		log.debug("Context is {}, checking tokens..",context);

		ClientInfo client = null;
		Set<String> roles=new HashSet<>();
		try{
			client = AuthorizationProvider.instance.get().getClient();
			roles= new HashSet<>(client.getRoles());
		}catch(Throwable  e) {
			log.warn("Unable to get client info ",e);
			roles = new HashSet<>();
		}



		AuthenticatedUser toReturn =
				new AuthenticatedUser(client,roles, AccessTokenProvider.instance.get(),SecurityTokenProvider.instance.get(),context);

		log.info("Current User is {} ",toReturn);
		return toReturn;
	}


	@AllArgsConstructor
	@Getter
	public static class AuthenticatedUser {
		private ClientInfo user;

		private Set<String> roles;

		private String uma_token;

		private String gcube_token;

		private String context;

		@Override
		public String toString() {
			StringBuilder builder = new StringBuilder();
			builder.append("User [user=");
			builder.append(user);
			builder.append(", uma_token=");
			builder.append(uma_token==null?uma_token:"***");

			builder.append(", gcube_token=");
			builder.append(gcube_token==null?gcube_token:"***");

			builder.append(", roles=");
			builder.append(roles);

			builder.append(", context=");
			builder.append(context);
			builder.append("]");
			return builder.toString();
		}

		public AccountingInfo asInfo(){
			AccountingInfo info=new AccountingInfo();
			User user = new User();
			try{
				user.setUsername(this.getUser().getId());
				user.setRoles(roles);
			}catch(Exception e){
				log.warn("Unable to determine user id, using FAKE",e);
				user.setUsername("fabio.sinibaldi");
				user.setRoles(new HashSet<>());
				user.getRoles().addAll(DEFAULT_ROLES);
			}

			info.setUser(user);
			info.setInstant(LocalDateTime.now());
			Context c=new Context();
			c.setId(this.context);
			c.setName(context.contains("/")?context.substring(context.lastIndexOf("/")):context);
			info.setContext(c);
			return info;
		}

	}
}
