using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json;
using e_suite.Database.Audit.Attributes;
using e_suite.Database.Core.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;

namespace e_suite.Database.Core.Tables.Workflow;

[DisplayName("Workflow Version")]
[Table("WorkflowVersions", Schema = "Workflow")]
[Index(nameof(WorkflowId), nameof(Version), IsUnique = true)]
[Index(nameof(Guid), IsUnique = true)]
public class WorkflowVersion : IGeneralId, ISoftDeletable
{
    [Key]
    public long Id { get; set; }

    [Required]
    public Guid Guid { get; set; } = Guid.NewGuid();

    public long WorkflowId { get; set; }

    [Required]
    public long Version { get; set; } = 1;

    [Required]
    public long DomainId { get; set; }

    [AuditName]
    [Required]
    public string ActivityNameTemplate { get; set; } = string.Empty;

    [Required]
    public string Description { get; set; } = string.Empty;

    public List<TaskDefinition> Tasks { get; set; } = [];

    [AuditSoftDelete(true)]
    [Required]
    [DefaultValue(false)]
    public bool Deleted { get; set; }

    [AuditParent]
    [ForeignKey(nameof(DomainId))]
    public virtual Domain.Domain Domain { get; set; } = null!;

    [AuditParent]
    [ForeignKey(nameof(WorkflowId))]
    public virtual Workflow Workflow { get; set; } = null!;

    [AuditLastUpdated]
    public DateTimeOffset LastUpdated { get; set; }

    private static readonly JsonSerializerOptions JsonOptions = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        WriteIndented = false
    };


    public static void OnModelCreating(ModelBuilder modelBuilder)
    {
        var comparer = new ValueComparer<List<TaskDefinition>>(
            (a, b) => a != null && b != null && a.SequenceEqual(b),
            v => v.Aggregate(0, (hash, item) => HashCode.Combine(hash, item.GetHashCode())),
            v => v.Select(item => item).ToList()
        );

        modelBuilder.Entity<WorkflowVersion>()
            .Property(w => w.Tasks)
            .HasConversion(
                v => JsonSerializer.Serialize(v, JsonOptions),
                v => JsonSerializer.Deserialize<List<TaskDefinition>>(v, JsonOptions) ?? new List<TaskDefinition>()
            )
            .Metadata.SetValueComparer(comparer);
    }
}