package com.eactive.eai.authserver.dao;

import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;

import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.message.mapper.EAIMessageMapper;
import com.eactive.eai.data.entity.onl.message.EAIMessageEntity;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.eactive.eai.authserver.dao.ClientLoader;
import com.eactive.eai.authserver.vo.ClientVO;
import com.eactive.eai.common.dao.BaseDAO;
import com.eactive.eai.common.dao.DAOException;
import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.data.converter.LocalDateTimeFormatters;
import com.eactive.eai.data.entity.onl.authserver.ClientEntity;

@Service
@Transactional
public class ClientDAO extends BaseDAO {
	static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);

	@Autowired
	private ClientLoader clientService;

	@Autowired
	private EAIMessageMapper eaiMessageMapper;

	public Map<String, ClientDetails> loadClientDetails() throws DAOException {
		try {
			Stream<ClientEntity> clientEntities = clientService.loadAll();
			Map<String, ClientDetails> clientDetailsMap = new HashMap<>();

			clientEntities.forEach(clientEntity -> {
				ClientVO clientVO = createClientVO(clientEntity);
				clientDetailsMap.put(clientEntity.getClientid(), clientVO);
			});
			return clientDetailsMap;

		} catch (Exception e) {
			throw new DAOException(ExceptionUtil.getErrorCode(e, "RECEAIAUC001"));
		}
	}

	public ClientVO getClientById(String clientId) throws DAOException {
		try {
			Optional<ClientEntity> clientEntityOptional = clientService.findById(clientId);
			ClientEntity clientEntity = clientEntityOptional
					.orElseThrow(() -> new DAOException("ClientEntity not found for clientId: " + clientId));

			return createClientVO(clientEntity);
		} catch (Exception e) {
			throw new DAOException(ExceptionUtil.getErrorCode(e, "RECEAIAUC001"));
		}
	}

	private ClientVO createClientVO(ClientEntity clientEntity) {
		ClientVO clientVO = new ClientVO();
		clientVO.setClientName(clientEntity.getClientname());
		clientVO.setClientId(clientEntity.getClientid());
		clientVO.setClientSecret(clientEntity.getClientsecret());
		clientVO.setScope(assignSet(clientEntity.getScope(), ","));
		clientVO.setAuthorizedGrantTypes(assignSet(clientEntity.getGranttypes(), ","));
		clientVO.setRegisteredRedirectUri(assignSet(clientEntity.getRedirecturi(), ","));
		clientVO.setAuthorities(assignAuthorities(clientEntity.getAuthorities()));
		clientVO.setResourceIds(assignSet(clientEntity.getResourceids(), ","));
		if (NumberUtils.isParsable(clientEntity.getAccesstokenvalidityseconds())) {
			clientVO.setAccessTokenValiditySeconds(Integer.parseInt(clientEntity.getAccesstokenvalidityseconds()));
		}
		if (NumberUtils.isParsable(clientEntity.getRefreshtokenvalidityseconds())) {
			clientVO.setRefreshTokenValiditySeconds(Integer.parseInt(clientEntity.getRefreshtokenvalidityseconds()));
		}
		clientVO.setAutoApproveScopes(assignSet(clientEntity.getAutoapprove(), ","));
		clientVO.setAllowedIp(clientEntity.getAllowedips());
		clientVO.setSecurityKey(clientEntity.getSecuritykey());
		clientVO.setModifiedBy(clientEntity.getModifiedby());
		clientVO.setOrgId(clientEntity.getModifiedby());
		clientVO.setModifiedBy(clientEntity.getModifiedby());
		clientVO.setOrgId(clientEntity.getOrgid());
		clientVO.setOrgName(clientEntity.getOrgname());
		clientVO.setAppStatus(clientEntity.getAppstatus());
		clientVO.setDailyTokenLimit(clientEntity.getDailytokenlimit());

		if(clientEntity.getModifiedon() != null) {
			clientVO.setModifiedOn(clientEntity.getModifiedon().format(LocalDateTimeFormatters.FORMATTER_YYYYMMDDHHMMSS_14));
		}

		Map<String, EAIMessage> apiMap = new HashMap<>();

		for (EAIMessageEntity eaiMessageEntity : clientEntity.getApiList()){
			EAIMessage eaiMessage = eaiMessageMapper.toVo(eaiMessageEntity);
			apiMap.put(eaiMessage.getEAISvcCd(), eaiMessage);
		}

		clientVO.setApiMap(apiMap);
		
		return clientVO;
	}

	private Collection<? extends GrantedAuthority> assignAuthorities(String roleStr) {
		List<GrantedAuthority> authorities = new ArrayList<>();

		if (StringUtils.isBlank(roleStr)) {
			return authorities;
		}

		for (String role : StringUtils.split(roleStr, ",")) {
			authorities.add(new SimpleGrantedAuthority(role));
		}

		return authorities;
	}

	private Set<String> assignSet(String str, String delim) {
		Set<String> set = new HashSet<>();

		if (StringUtils.isBlank(str)) {
			return set;
		}

		String[] arr = StringUtils.split(str, delim);
		set.addAll(Arrays.asList(arr));

		return set;
	}
}
