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

import com.fasterxml.jackson.annotation.JsonInclude;
import dev.lions.user.manager.dto.base.BaseDTO;
import dev.lions.user.manager.enums.role.TypeRole;
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.util.List;
import java.util.Map;

/**
 * DTO représentant un rôle Keycloak
 * Mappé depuis RoleRepresentation de Keycloak Admin API
 */
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
@Schema(description = "Rôle Keycloak (Realm ou Client)")
@RegisterForReflection
public class RoleDTO extends BaseDTO {

    private static final long serialVersionUID = 1L;

    @NotBlank(message = "Le nom du rôle est obligatoire")
    @Size(min = 2, max = 100, message = "Le nom du rôle doit contenir entre 2 et 100 caractères")
    @Pattern(regexp = "^[a-zA-Z0-9_-]+$", message = "Le nom du rôle ne peut contenir que des lettres, chiffres, underscores et tirets")
    @Schema(description = "Nom du rôle", example = "admin_btpxpress", required = true)
    private String name;

    @Schema(description = "Description du rôle", example = "Administrateur avec tous les privilèges")
    private String description;

    @Schema(description = "Type de rôle", example = "REALM_ROLE")
    private TypeRole typeRole;

    @Schema(description = "Indique si c'est un rôle composite", example = "false")
    private Boolean composite;

    @Schema(description = "ID du conteneur (Realm ou Client)", example = "btpxpress")
    private String containerId;

    @Schema(description = "Nom du Realm", example = "btpxpress")
    private String realmName;

    @Schema(description = "Nom du Client (si rôle client)", example = "btpxpress-app")
    private String clientName;

    @Schema(description = "ID du Client (si rôle client)")
    private String clientId;

    @Schema(description = "Rôles composites inclus dans ce rôle")
    private List<String> compositeRoles;

    @Schema(description = "Rôles Realm composites")
    private List<RoleCompositeDTO> compositeRealmRoles;

    @Schema(description = "Rôles Client composites par client")
    private Map<String, List<RoleCompositeDTO>> compositeClientRoles;

    @Schema(description = "Attributs personnalisés du rôle")
    private Map<String, List<String>> attributes;

    @Schema(description = "Nombre d'utilisateurs ayant ce rôle", example = "15")
    private Integer userCount;

    @Schema(description = "Indique si le rôle est un rôle système", example = "false")
    private Boolean systemRole;

    @Schema(description = "Indique si le rôle peut être supprimé", example = "true")
    private Boolean deletable;

    /**
     * Détermine si c'est un rôle Realm
     * @return true si typeRole est REALM_ROLE
     */
    public boolean isRealmRole() {
        return typeRole == TypeRole.REALM_ROLE;
    }

    /**
     * Détermine si c'est un rôle Client
     * @return true si typeRole est CLIENT_ROLE
     */
    public boolean isClientRole() {
        return typeRole == TypeRole.CLIENT_ROLE;
    }

    /**
     * Détermine si le rôle est composite
     * @return true si composite = true et a des rôles composites
     */
    public boolean isComposite() {
        return Boolean.TRUE.equals(composite)
            && ((compositeRoles != null && !compositeRoles.isEmpty())
                || (compositeRealmRoles != null && !compositeRealmRoles.isEmpty())
                || (compositeClientRoles != null && !compositeClientRoles.isEmpty()));
    }

    /**
     * Retourne le nom complet du rôle (avec préfixe client si applicable)
     * @return nom complet
     */
    public String getFullName() {
        if (isClientRole() && clientName != null) {
            return clientName + ":" + name;
        }
        return name;
    }

    /**
     * DTO pour rôle composite
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @SuperBuilder
    @Schema(description = "Rôle composite")
    public static class RoleCompositeDTO {
        @Schema(description = "ID du rôle", example = "f47ac10b-58cc-4372-a567-0e02b2c3d479")
        private String id;

        @Schema(description = "Nom du rôle", example = "gestionnaire")
        private String name;

        @Schema(description = "Description du rôle")
        private String description;

        @Schema(description = "Type de rôle", example = "REALM_ROLE")
        private TypeRole typeRole;

        @Schema(description = "Nom du client (si client role)")
        private String clientName;
    }
}
