package com.social.media.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;

import java.time.LocalDateTime;

/**
 * Data Transfer Object for UserCredentials
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserCredentialsDto {
    
    @NotNull(message = "User ID is required")
    @Positive(message = "User ID must be positive")
    private Long userId;
    
    @JsonIgnore // Never expose password hash in API responses
    private String passwordHash;
    
    @Min(value = 0, message = "Failed login attempts cannot be negative")
    @Max(value = 10, message = "Failed login attempts cannot exceed 10")
    private Integer failedLoginAttempts;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime lockedUntil;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime lastLoginAt;
    
    @JsonIgnore // Never expose reset tokens in API responses
    private String passwordResetToken;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime passwordResetExpiresAt;
    
    @JsonIgnore // Never expose verification tokens in API responses
    private String emailVerificationToken;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime passwordChangedAt;
    
    @NotNull(message = "Two-factor enabled flag is required")
    private Boolean twoFactorEnabled;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createdAt;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updatedAt;
    
    // Computed/derived fields for UI and business logic
    
    @JsonProperty("isAccountLocked")
    private Boolean isAccountLocked;
    
    @JsonProperty("isPermanentlyLocked")
    private Boolean isPermanentlyLocked;
    
    @JsonProperty("isPasswordResetTokenValid")
    private Boolean isPasswordResetTokenValid;
    
    @JsonProperty("hasEmailVerificationToken")
    private Boolean hasEmailVerificationToken;
    
    @JsonProperty("isPasswordRecentlyChanged")
    private Boolean isPasswordRecentlyChanged;
    
    @JsonProperty("hasRecentLogin")
    private Boolean hasRecentLogin;
    
    @JsonProperty("needsSecurityReview")
    private Boolean needsSecurityReview;
    
    @JsonProperty("securityStatus")
    private String securityStatus;
    
    @JsonProperty("lockoutDurationMinutes")
    private Integer lockoutDurationMinutes;
    
    @JsonProperty("maxFailedAttempts")
    private Integer maxFailedAttempts;
    
    @JsonProperty("daysSinceLastLogin")
    private Long daysSinceLastLogin;
    
    @JsonProperty("daysSincePasswordChanged")
    private Long daysSincePasswordChanged;
    
    @JsonProperty("remainingLockoutMinutes")
    private Long remainingLockoutMinutes;
    
    // Helper methods for UI display
    
    /**
     * Get user-friendly security status description
     */
    public String getSecurityStatusDescription() {
        if (securityStatus == null) return "Unknown";
        
        return switch (securityStatus) {
            case "PERMANENTLY_LOCKED" -> "Account permanently locked due to security violations";
            case "TEMPORARILY_LOCKED" -> "Account temporarily locked due to failed login attempts";
            case "FAILED_ATTEMPTS" -> "Recent failed login attempts detected";
            case "SECURED_2FA" -> "Account secured with two-factor authentication";
            case "ACTIVE" -> "Account active with recent login activity";
            case "INACTIVE" -> "Account inactive - no recent login activity";
            default -> "Unknown security status";
        };
    }
    
    /**
     * Get security risk level
     */
    public String getSecurityRiskLevel() {
        if (Boolean.TRUE.equals(isPermanentlyLocked)) return "CRITICAL";
        if (Boolean.TRUE.equals(isAccountLocked)) return "HIGH";
        if (failedLoginAttempts != null && failedLoginAttempts >= 3) return "MEDIUM";
        if (Boolean.TRUE.equals(needsSecurityReview)) return "MEDIUM";
        if (Boolean.FALSE.equals(twoFactorEnabled) && Boolean.TRUE.equals(hasRecentLogin)) return "LOW";
        if (Boolean.TRUE.equals(twoFactorEnabled)) return "VERY_LOW";
        return "LOW";
    }
    
    /**
     * Get recommended security actions
     */
    public String getRecommendedAction() {
        if (Boolean.TRUE.equals(isPermanentlyLocked)) {
            return "Contact administrator for account unlock";
        }
        if (Boolean.TRUE.equals(isAccountLocked)) {
            return "Wait for lockout period to expire or contact support";
        }
        if (failedLoginAttempts != null && failedLoginAttempts >= 2) {
            return "Verify login credentials to avoid account lockout";
        }
        if (Boolean.FALSE.equals(twoFactorEnabled)) {
            return "Enable two-factor authentication for enhanced security";
        }
        if (daysSincePasswordChanged != null && daysSincePasswordChanged > 90) {
            return "Consider changing password for better security";
        }
        if (Boolean.FALSE.equals(hasRecentLogin) && lastLoginAt != null) {
            return "Account appears inactive - verify if still needed";
        }
        return "No immediate action required";
    }
    
    /**
     * Check if account can attempt login
     */
    public boolean canAttemptLogin() {
        return !Boolean.TRUE.equals(isAccountLocked) && !Boolean.TRUE.equals(isPermanentlyLocked);
    }
    
    /**
     * Check if account needs immediate attention
     */
    public boolean needsImmediateAttention() {
        return Boolean.TRUE.equals(isPermanentlyLocked) || 
               Boolean.TRUE.equals(needsSecurityReview) ||
               (failedLoginAttempts != null && failedLoginAttempts >= 4);
    }
    
    /**
     * Get security score (0-100, higher is more secure)
     */
    public int getSecurityScore() {
        int score = 50; // Base score
        
        // Two-factor authentication adds significant security
        if (Boolean.TRUE.equals(twoFactorEnabled)) {
            score += 30;
        }
        
        // Recent login activity is positive
        if (Boolean.TRUE.equals(hasRecentLogin)) {
            score += 10;
        }
        
        // Recent password change is good
        if (Boolean.TRUE.equals(isPasswordRecentlyChanged)) {
            score += 10;
        }
        
        // Deduct points for security issues
        if (Boolean.TRUE.equals(isPermanentlyLocked)) {
            score = 0;
        } else if (Boolean.TRUE.equals(isAccountLocked)) {
            score -= 40;
        } else if (failedLoginAttempts != null && failedLoginAttempts > 0) {
            score -= (failedLoginAttempts * 10);
        }
        
        // Old passwords reduce security
        if (daysSincePasswordChanged != null) {
            if (daysSincePasswordChanged > 180) {
                score -= 20;
            } else if (daysSincePasswordChanged > 90) {
                score -= 10;
            }
        }
        
        // Inactive accounts are less secure
        if (daysSinceLastLogin != null && daysSinceLastLogin > 90) {
            score -= 15;
        }
        
        return Math.max(0, Math.min(100, score));
    }
    
    /**
     * Get display-friendly time until unlock
     */
    public String getTimeUntilUnlock() {
        if (remainingLockoutMinutes == null || remainingLockoutMinutes <= 0) {
            return "Not locked";
        }
        
        if (remainingLockoutMinutes < 60) {
            return remainingLockoutMinutes + " minutes";
        } else if (remainingLockoutMinutes < 1440) {
            long hours = remainingLockoutMinutes / 60;
            long minutes = remainingLockoutMinutes % 60;
            return hours + " hours" + (minutes > 0 ? " " + minutes + " minutes" : "");
        } else {
            long days = remainingLockoutMinutes / 1440;
            long hours = (remainingLockoutMinutes % 1440) / 60;
            return days + " days" + (hours > 0 ? " " + hours + " hours" : "");
        }
    }
    
    /**
     * Check if password reset token is about to expire (within 1 hour)
     */
    public boolean isPasswordResetTokenExpiringSoon() {
        return passwordResetExpiresAt != null && 
               passwordResetExpiresAt.isAfter(LocalDateTime.now()) &&
               passwordResetExpiresAt.isBefore(LocalDateTime.now().plusHours(1));
    }
    
    /**
     * Get days until password expiry (assuming 90-day policy)
     */
    public Long getDaysUntilPasswordExpiry() {
        if (passwordChangedAt == null) return null;
        
        LocalDateTime expiryDate = passwordChangedAt.plusDays(90);
        LocalDateTime now = LocalDateTime.now();
        
        if (expiryDate.isBefore(now)) return 0L; // Already expired
        
        return java.time.Duration.between(now, expiryDate).toDays();
    }
    
    /**
     * Check if this is a new account (created within last 7 days)
     */
    public boolean isNewAccount() {
        return createdAt != null && createdAt.isAfter(LocalDateTime.now().minusDays(7));
    }
}
