package de.szut.casino.security.oauth2.github;

import de.szut.casino.security.dto.AuthResponseDto;
import de.szut.casino.security.jwt.JwtUtils;
import de.szut.casino.user.AuthProvider;
import de.szut.casino.user.UserEntity;
import de.szut.casino.user.UserRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.*;

@Service
public class GitHubService {
    @Value("${spring.security.oauth2.client.registration.github.client-id}")
    private String clientId;

    @Value("${spring.security.oauth2.client.registration.github.client-secret}")
    private String clientSecret;

    private final AuthenticationManager authenticationManager;
    private final UserRepository userRepository;
    private final JwtUtils jwtUtils;
    private final PasswordEncoder oauth2PasswordEncoder;

    public GitHubService(AuthenticationManager authenticationManager, UserRepository userRepository, JwtUtils jwtUtils, PasswordEncoder oauth2PasswordEncoder) {
        this.authenticationManager = authenticationManager;
        this.userRepository = userRepository;
        this.jwtUtils = jwtUtils;
        this.oauth2PasswordEncoder = oauth2PasswordEncoder;
    }

    public AuthResponseDto processGithubCode(String code) {
        try {
            RestTemplate restTemplate = new RestTemplate();

            Map<String, String> requestBody = new HashMap<>();
            requestBody.put("client_id", clientId);
            requestBody.put("client_secret", clientSecret);
            requestBody.put("code", code);

            HttpHeaders headers = new HttpHeaders();
            headers.set("Accept", "application/json");

            HttpEntity<Map<String, String>> requestEntity = new HttpEntity<>(requestBody, headers);

            ResponseEntity<Map> response = restTemplate.exchange(
                    "https://github.com/login/oauth/access_token",
                    HttpMethod.POST,
                    requestEntity,
                    Map.class
            );

            Map<String, Object> responseBody = response.getBody();

            if (responseBody.containsKey("error")) {
                String error = (String) responseBody.get("error");
                String errorDescription = (String) responseBody.get("error_description");

                throw new RuntimeException("GitHub OAuth error: " + errorDescription);
            }

            String accessToken = (String) responseBody.get("access_token");
            if (accessToken == null || accessToken.isEmpty()) {

                throw new RuntimeException("Failed to receive access token from GitHub");
            }

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

            HttpEntity<String> userInfoRequestEntity = new HttpEntity<>(null, userInfoHeaders);

            ResponseEntity<Map> userResponse = restTemplate.exchange(
                    "https://api.github.com/user",
                    HttpMethod.GET,
                    userInfoRequestEntity,
                    Map.class
            );

            Map<String, Object> userAttributes = userResponse.getBody();

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

            HttpEntity<String> emailsRequestEntity = new HttpEntity<>(null, emailsHeaders);

            ResponseEntity<List> emailsResponse = restTemplate.exchange(
                    "https://api.github.com/user/emails",
                    HttpMethod.GET,
                    emailsRequestEntity,
                    List.class
            );

            List<Map<String, Object>> emails = emailsResponse.getBody();
            String email = null;

            for (Map<String, Object> emailInfo : emails) {
                Boolean primary = (Boolean) emailInfo.get("primary");
                if (primary != null && primary) {
                    email = (String) emailInfo.get("email");
                    break;
                }
            }

            if (email == null && !emails.isEmpty()) {
                email = (String) emails.get(0).get("email");
            }

            String githubId = userAttributes.get("id").toString();
            String username = (String) userAttributes.get("login");

            Optional<UserEntity> userOptional = userRepository.findByProviderId(githubId);
            UserEntity user;

            if (userOptional.isPresent()) {
                user = userOptional.get();
            } else {
                userOptional = userRepository.findByEmail(email);

                if (userOptional.isPresent()) {
                    user = userOptional.get();
                    user.setProvider(AuthProvider.GITHUB);
                    user.setProviderId(githubId);
                } else {
                    user = new UserEntity();
                    user.setEmail(email);
                    user.setUsername(username);
                    user.setProvider(AuthProvider.GITHUB);
                    user.setProviderId(githubId);
                    user.setEmailVerified(true);

                    user.setBalance(new BigDecimal("1000.00"));
                }
            }

            String randomPassword = UUID.randomUUID().toString();
            user.setPassword(oauth2PasswordEncoder.encode(randomPassword));

            userRepository.save(user);

            Authentication authentication = this.authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getEmail(), randomPassword));

            String token = jwtUtils.generateToken(authentication);

            return new AuthResponseDto(token);

        } catch (Exception e) {
            throw new RuntimeException("Failed to process GitHub authentication", e);
        }
    }
}
