package it.enea.cruise.service.idp;

import it.enea.cruise.exceptions.TokenNotValidException;
import it.enea.cruise.repositories.UserRepository;
import it.enea.scp.idp.sdk.model.UserDto;
import it.enea.cruise.model.user.User;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
@Profile({"dev",  "oid"})
@Transactional
public class KeycloakProvider implements IdpProvider {
	@Value("${idp.auth-server-url}")
	private String serverUrl;

	@Value("${idp.realm}")
	private String realm;

	@Value("${idp.clientId}")
	private String clientId;

	@Value("${idp.clientSecret}")
	private String clientSecret;

	private final UserRepository userRepository;

	@Override
	public String getTokenFromUsernameAndPassword(String username, String password) {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public User login(String username, String password) {
		return null;
	}

	@Override
	public boolean logout(String token) {
		return false;
	}

	@Override
	public boolean isValid(String token) {
		return isTokenValid(token);
	}

	@Override
	public List<UserDto> userList() {
		return List.of();
	}

	@Override
	public Boolean deleteUser(String email) {
		return null;
	}

	@Override
	public Boolean createUser(UserDto newUser) {
		return null;
	}

	@Override
	public UserDto getUserByEmail(String email) {
		return null;
	}

	@Override
	public User getUserByToken(String token) {
		if (token != null && isTokenValid(token)) {
			Map<String, Object> userInfo = getUserInfo(token);
			String subject = (String) userInfo.get("sub");

			if (subject == null || subject.isBlank()) {
				throw new RuntimeException("KeyCloak provider: subject not present in OID response");
			}

			User dbUser = userRepository.findUserBySubject(subject);

			if (dbUser == null) {
				throw new RuntimeException("KeyCloak provider: subject not present in OID response");
			}

			log.info("User info is {}", userInfo);
			return dbUser;
		}

		throw new TokenNotValidException(String.format("Token %s, is not valid", token));
	}

	@Override
	public Boolean updateUser(UserDto user) {
		return null;
	}

	@Override
	public UserDto getUserFromUUID(String uuid) {
		return null;
	}

	@Override
	public Boolean updatePassword(String token, String password) {
		return null;
	}

	public boolean isTokenValid(String accessToken) {
		String url = String.format("%s/realms/%s/protocol/openid-connect/token/introspect", serverUrl, realm);
		RestTemplate restTemplate = new RestTemplate();

		HttpHeaders headers = new HttpHeaders();
		headers.setBasicAuth(clientId, clientSecret);
		headers.setContentType(org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED);

		String body = String.format("token=%s", accessToken);
		HttpEntity<String> entity = new HttpEntity<>(body, headers);

		ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.POST, entity, Map.class);
		Map<String, Object> responseBody = response.getBody();

		return responseBody != null && Boolean.TRUE.equals(responseBody.get("active"));
	}

	public Map<String, Object> getUserInfo(String accessToken) {
		String url = String.format("%s/realms/%s/protocol/openid-connect/userinfo", serverUrl, realm);
		RestTemplate restTemplate = new RestTemplate();

		HttpHeaders headers = new HttpHeaders();
		headers.set("Authorization", "Bearer " + accessToken);

		HttpEntity<String> entity = new HttpEntity<>(headers);

		ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.GET, entity, Map.class);

		return response.getBody();
	}
}
