package dev.lions.user.manager.dto.user;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.lions.user.manager.dto.base.BaseDTO;
import dev.lions.user.manager.enums.user.StatutUser;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import io.quarkus.runtime.annotations.RegisterForReflection;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * DTO représentant un utilisateur Keycloak
 * Mappé depuis la représentation UserRepresentation de Keycloak Admin API
 */
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
@Schema(description = "Utilisateur Keycloak")
@RegisterForReflection
public class UserDTO extends BaseDTO {

    private static final long serialVersionUID = 1L;

    // Informations de base
    @NotBlank(message = "Le nom d'utilisateur est obligatoire")
    @Size(min = 3, max = 100, message = "Le nom d'utilisateur doit contenir entre 3 et 100 caractères")
    @Pattern(regexp = "^[a-zA-Z0-9._-]+$", message = "Le nom d'utilisateur ne peut contenir que des lettres, chiffres, points, tirets et underscores")
    @Schema(description = "Nom d'utilisateur unique", example = "jdupont", required = true)
    private String username;

    @NotBlank(message = "L'email est obligatoire")
    @Email(message = "Format d'email invalide")
    @Schema(description = "Adresse email", example = "jean.dupont@lions.dev", required = true)
    private String email;

    @Schema(description = "Email vérifié", example = "true")
    private Boolean emailVerified;

    @NotBlank(message = "Le prénom est obligatoire")
    @Size(min = 2, max = 100, message = "Le prénom doit contenir entre 2 et 100 caractères")
    @Schema(description = "Prénom", example = "Jean", required = true)
    private String prenom;

    @NotBlank(message = "Le nom est obligatoire")
    @Size(min = 2, max = 100, message = "Le nom doit contenir entre 2 et 100 caractères")
    @Schema(description = "Nom de famille", example = "Dupont", required = true)
    private String nom;

    // Statut
    @Schema(description = "Statut de l'utilisateur", example = "ACTIF")
    private StatutUser statut;

    @Schema(description = "Compte activé", example = "true")
    private Boolean enabled;

    // Informations supplémentaires
    @Schema(description = "Numéro de téléphone", example = "+225 07 12 34 56 78")
    private String telephone;

    @Schema(description = "Organisation/Entreprise", example = "Lions Dev")
    private String organisation;

    @Schema(description = "Département", example = "IT")
    private String departement;

    @Schema(description = "Fonction/Poste", example = "Développeur Senior")
    private String fonction;

    @Schema(description = "Pays", example = "Côte d'Ivoire")
    private String pays;

    @Schema(description = "Ville", example = "Abidjan")
    private String ville;

    @Schema(description = "Langue préférée", example = "fr")
    private String langue;

    @Schema(description = "Fuseau horaire", example = "Africa/Abidjan")
    private String timezone;

    // Realm et rôles
    @Schema(description = "Realm Keycloak", example = "btpxpress")
    private String realmName;

    @Schema(description = "Liste des rôles Realm assignés")
    private List<String> realmRoles;

    @Schema(description = "Liste des rôles Client assignés")
    private Map<String, List<String>> clientRoles;

    @Schema(description = "Liste des groupes auxquels appartient l'utilisateur")
    private List<String> groups;

    // Dates importantes
    @Schema(description = "Date de dernière connexion", example = "2025-01-15T10:30:00")
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
    private LocalDateTime derniereConnexion;

    @Schema(description = "Date d'expiration du compte", example = "2026-01-15T23:59:59")
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
    private LocalDateTime dateExpiration;

    @Schema(description = "Date de verrouillage du compte", example = "2025-01-15T16:00:00")
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
    private LocalDateTime dateVerrouillage;

    // Attributs personnalisés Keycloak
    @Schema(description = "Attributs personnalisés Keycloak")
    private Map<String, List<String>> attributes;

    // Actions requises
    @Schema(description = "Actions requises (ex: UPDATE_PASSWORD, VERIFY_EMAIL)")
    private List<String> requiredActions;

    // Fédération
    @Schema(description = "Fournisseur d'identité fédéré", example = "google")
    private String federatedIdentityProvider;

    @Schema(description = "Lien d'identité fédérée")
    private List<FederatedIdentityDTO> federatedIdentities;

    // Crédentiels temporaires
    @Schema(description = "Mot de passe temporaire (création uniquement)")
    private String temporaryPassword;

    @Schema(description = "Indique si le mot de passe est temporaire")
    private Boolean temporaryPasswordFlag;

    // Informations de session
    @Schema(description = "Nombre de sessions actives", example = "2")
    private Integer activeSessions;

    @Schema(description = "Nombre d'échecs de connexion", example = "0")
    private Integer failedLoginAttempts;

    // Audit
    @Schema(description = "Raison de la dernière modification")
    private String raisonModification;

    @Schema(description = "Commentaires administratifs")
    private String commentaires;

    /**
     * Retourne le nom complet de l'utilisateur
     * @return prénom + nom
     */
    public String getNomComplet() {
        if (prenom != null && nom != null) {
            return prenom + " " + nom;
        }
        return username;
    }

    /**
     * Détermine si l'utilisateur est actif
     * @return true si statut ACTIF et enabled
     */
    public boolean isActif() {
        return statut == StatutUser.ACTIF && Boolean.TRUE.equals(enabled);
    }

    /**
     * Détermine si le compte a expiré
     * @return true si dateExpiration est passée
     */
    public boolean isExpire() {
        return dateExpiration != null && dateExpiration.isBefore(LocalDateTime.now());
    }

    /**
     * Détermine si l'utilisateur a des actions requises
     * @return true si des actions sont requises
     */
    public boolean hasRequiredActions() {
        return requiredActions != null && !requiredActions.isEmpty();
    }

    /**
     * DTO pour identité fédérée
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @SuperBuilder
    @Schema(description = "Identité fédérée")
    public static class FederatedIdentityDTO {
        @Schema(description = "Fournisseur d'identité", example = "google")
        private String identityProvider;

        @Schema(description = "ID utilisateur chez le fournisseur")
        private String userId;

        @Schema(description = "Nom d'utilisateur chez le fournisseur")
        private String userName;
    }
}
