namespace Apollinare.Domain.Entities;

/// <summary>
/// Dataset virtuale creato dall'utente combinando più dataset con relazioni e filtri.
/// Permette di creare "viste" composite che appaiono come dataset normali nel report designer.
/// </summary>
public class VirtualDataset : BaseEntity
{
    /// <summary>
    /// Nome identificativo del dataset virtuale (usato come ID)
    /// </summary>
    public string Nome { get; set; } = string.Empty;

    /// <summary>
    /// Nome visualizzato nell'interfaccia
    /// </summary>
    public string DisplayName { get; set; } = string.Empty;

    /// <summary>
    /// Descrizione del dataset
    /// </summary>
    public string? Descrizione { get; set; }

    /// <summary>
    /// Icona per l'interfaccia (nome icona Material-UI)
    /// </summary>
    public string Icon { get; set; } = "dataset";

    /// <summary>
    /// Categoria del dataset (per raggruppamento)
    /// </summary>
    public string Categoria { get; set; } = "Personalizzato";

    /// <summary>
    /// Configurazione JSON del dataset virtuale
    /// Contiene: sources, relationships, filters, outputFields
    /// </summary>
    public string ConfigurationJson { get; set; } = "{}";

    /// <summary>
    /// Se il dataset è attivo e disponibile per la selezione
    /// </summary>
    public bool Attivo { get; set; } = true;
}

/// <summary>
/// Modello per la configurazione del dataset virtuale (serializzato in ConfigurationJson)
/// </summary>
public class VirtualDatasetConfiguration
{
    /// <summary>
    /// Dataset sorgente (tabelle base)
    /// </summary>
    public List<VirtualDatasetSource> Sources { get; set; } = new();

    /// <summary>
    /// Relazioni tra i dataset sorgente (JOIN)
    /// </summary>
    public List<VirtualDatasetRelationship> Relationships { get; set; } = new();

    /// <summary>
    /// Filtri globali applicati al dataset
    /// </summary>
    public List<VirtualDatasetFilter> Filters { get; set; } = new();

    /// <summary>
    /// Campi di output selezionati (se vuoto, tutti i campi)
    /// </summary>
    public List<VirtualDatasetOutputField> OutputFields { get; set; } = new();

    /// <summary>
    /// Dataset primario (root) da cui partire
    /// </summary>
    public string? PrimarySourceId { get; set; }
}

/// <summary>
/// Dataset sorgente incluso nel dataset virtuale
/// </summary>
public class VirtualDatasetSource
{
    /// <summary>
    /// ID univoco della sorgente nel contesto del virtual dataset
    /// </summary>
    public string Id { get; set; } = string.Empty;

    /// <summary>
    /// ID del dataset base (es. "evento", "cliente", "articolo")
    /// </summary>
    public string DatasetId { get; set; } = string.Empty;

    /// <summary>
    /// Alias per riferirsi a questo dataset nelle espressioni
    /// </summary>
    public string Alias { get; set; } = string.Empty;

    /// <summary>
    /// Se è il dataset principale (root)
    /// </summary>
    public bool IsPrimary { get; set; }
}

/// <summary>
/// Relazione tra due dataset sorgente (JOIN)
/// </summary>
public class VirtualDatasetRelationship
{
    /// <summary>
    /// ID univoco della relazione
    /// </summary>
    public string Id { get; set; } = string.Empty;

    /// <summary>
    /// ID sorgente del lato sinistro (from)
    /// </summary>
    public string FromSourceId { get; set; } = string.Empty;

    /// <summary>
    /// Campo chiave del lato sinistro
    /// </summary>
    public string FromField { get; set; } = string.Empty;

    /// <summary>
    /// ID sorgente del lato destro (to)
    /// </summary>
    public string ToSourceId { get; set; } = string.Empty;

    /// <summary>
    /// Campo chiave del lato destro
    /// </summary>
    public string ToField { get; set; } = string.Empty;

    /// <summary>
    /// Tipo di JOIN: inner, left, right
    /// </summary>
    public string JoinType { get; set; } = "left";

    /// <summary>
    /// Nome descrittivo della relazione
    /// </summary>
    public string? Label { get; set; }
}

/// <summary>
/// Filtro applicato al dataset virtuale
/// </summary>
public class VirtualDatasetFilter
{
    /// <summary>
    /// ID univoco del filtro
    /// </summary>
    public string Id { get; set; } = string.Empty;

    /// <summary>
    /// ID della sorgente a cui applicare il filtro
    /// </summary>
    public string SourceId { get; set; } = string.Empty;

    /// <summary>
    /// Campo su cui filtrare
    /// </summary>
    public string Field { get; set; } = string.Empty;

    /// <summary>
    /// Operatore: eq, neq, gt, gte, lt, lte, contains, startsWith, endsWith, isNull, isNotNull
    /// </summary>
    public string Operator { get; set; } = "eq";

    /// <summary>
    /// Valore di confronto (può essere statico o parametrico {{param}})
    /// </summary>
    public string? Value { get; set; }

    /// <summary>
    /// Tipo del valore: static, parameter, field
    /// </summary>
    public string ValueType { get; set; } = "static";

    /// <summary>
    /// Operatore logico con il filtro successivo: and, or
    /// </summary>
    public string LogicalOperator { get; set; } = "and";

    /// <summary>
    /// Se il filtro è attivo
    /// </summary>
    public bool Enabled { get; set; } = true;
}

/// <summary>
/// Campo di output selezionato per il dataset virtuale
/// </summary>
public class VirtualDatasetOutputField
{
    /// <summary>
    /// ID univoco del campo output
    /// </summary>
    public string Id { get; set; } = string.Empty;

    /// <summary>
    /// ID della sorgente da cui proviene il campo
    /// </summary>
    public string SourceId { get; set; } = string.Empty;

    /// <summary>
    /// Nome del campo sorgente
    /// </summary>
    public string FieldName { get; set; } = string.Empty;

    /// <summary>
    /// Alias per il campo nell'output (se diverso dal nome originale)
    /// </summary>
    public string? Alias { get; set; }

    /// <summary>
    /// Label visualizzata
    /// </summary>
    public string? Label { get; set; }

    /// <summary>
    /// Gruppo logico per organizzazione UI
    /// </summary>
    public string? Group { get; set; }

    /// <summary>
    /// Ordine di visualizzazione
    /// </summary>
    public int Order { get; set; }

    /// <summary>
    /// Se includere il campo nell'output
    /// </summary>
    public bool Included { get; set; } = true;
}
