package com.gnx.telemedicine.service;

import com.gnx.telemedicine.model.LoginAttempt;
import com.gnx.telemedicine.model.UserModel;
import com.gnx.telemedicine.repository.LoginAttemptRepository;
import com.gnx.telemedicine.repository.UserRepository;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.UUID;

@Service
@RequiredArgsConstructor
public class LoginAttemptService {
    
    private final LoginAttemptRepository loginAttemptRepository;
    private final UserRepository userRepository;

    @Value("${security.login.max-attempts:5}")
    private int maxFailedAttempts;

    @Value("${security.login.lockout-duration-minutes:30}")
    private int lockoutDurationMinutes;

    @Transactional
    public void recordSuccessfulLogin(String email, HttpServletRequest request) {
        recordLoginAttempt(email, true, null, request);
        
        // Reset failed attempts counter
        UserModel user = userRepository.findByEmail(email).orElse(null);
        if (user != null) {
            user.setFailedLoginAttempts(0);
            user.setAccountLockedUntil(null);
            userRepository.save(user);
        }
    }

    @Transactional
    public void recordFailedLogin(String email, String reason, HttpServletRequest request) {
        recordLoginAttempt(email, false, reason, request);
        
        // Increment failed attempts counter
        UserModel user = userRepository.findByEmail(email).orElse(null);
        if (user != null) {
            int failedAttempts = (user.getFailedLoginAttempts() != null ? user.getFailedLoginAttempts() : 0) + 1;
            user.setFailedLoginAttempts(failedAttempts);
            user.setLastFailedLogin(Instant.now());

            // Lock account if max attempts reached
            if (failedAttempts >= maxFailedAttempts) {
                Instant lockoutUntil = Instant.now().plus(lockoutDurationMinutes, ChronoUnit.MINUTES);
                user.setAccountLockedUntil(lockoutUntil);
            }
            
            userRepository.save(user);
        }
    }

    @Transactional(readOnly = true)
    public boolean isAccountLocked(String email) {
        UserModel user = userRepository.findByEmail(email).orElse(null);
        if (user == null || user.getAccountLockedUntil() == null) {
            return false;
        }
        
        return Instant.now().isBefore(user.getAccountLockedUntil());
    }

    @Transactional(readOnly = true)
    public int getRemainingAttempts(String email) {
        UserModel user = userRepository.findByEmail(email).orElse(null);
        if (user == null) {
            return maxFailedAttempts;
        }
        
        int failedAttempts = user.getFailedLoginAttempts() != null ? user.getFailedLoginAttempts() : 0;
        return Math.max(0, maxFailedAttempts - failedAttempts);
    }

    @Transactional(readOnly = true)
    public Long getFailedAttemptsCount(String email, Instant since) {
        return loginAttemptRepository.countFailedAttemptsSince(email, since);
    }

    @Transactional(readOnly = true)
    public List<LoginAttempt> getRecentAttempts(String email, int hours) {
        Instant since = Instant.now().minus(hours, ChronoUnit.HOURS);
        return loginAttemptRepository.findRecentAttemptsByEmail(email, since);
    }

    private void recordLoginAttempt(String email, boolean success, String failureReason, HttpServletRequest request) {
        LoginAttempt attempt = new LoginAttempt();
        // Don't set ID manually - let Hibernate generate it via @GeneratedValue
        attempt.setEmail(email);
        attempt.setSuccess(success);
        attempt.setFailureReason(failureReason);
        attempt.setTimestamp(Instant.now());

        if (request != null) {
            attempt.setIpAddress(getClientIpAddress(request));
        }

        loginAttemptRepository.save(attempt);
    }

    private String getClientIpAddress(HttpServletRequest request) {
        String ipAddress = request.getHeader("X-Forwarded-For");
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
        }
        if (ipAddress != null && ipAddress.contains(",")) {
            ipAddress = ipAddress.split(",")[0].trim();
        }
        return ipAddress;
    }
}

