using NpgsqlTypes;
using Persic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics.CodeAnalysis;
using System.Text;

namespace OpenArchival.DataAccess;

public class ArtifactGrouping
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string? ArtifactGroupingIdentifier
    {
        get
        {
            return ModelHelpers.MakeIdentifier(IdentifierFields.Values, Category.FieldSeparator, null);
        }
    }

    [NotMapped]
    public List<FilePathListing> ChildFilePathListings
    {
        get
        {
            var list = new List<FilePathListing>();
            foreach (ArtifactEntry entry in ChildArtifactEntries)
            {
                list.AddRange(entry.Files);
            }

            return list;
        }
    }

    public required ArchiveCategory Category { get; set; }

    private IdentifierFields _identifierFields;
    public required IdentifierFields IdentifierFields
    {
        get => _identifierFields;
        set
        {
            if (value.Values.Count != Category.FieldNames.Count)
            {
                throw new ArgumentException(nameof(IdentifierFields), $"The number of field values must be equal to the field count of the {nameof(ArchiveCategory)}");
            }

            _identifierFields = value;
        }
    }

    public required string Title { get; set; }

    public string? Description { get; set; }

    public ArtifactType Type { get; set; }

    public bool IsPublicallyVisible { get; set; }

    public required List<ArtifactEntry> ChildArtifactEntries { get; set; } = new();

    public ArtifactGroupingViewCount? ViewCount { get; set; }
    
    /// <summary>
    /// The list of all blog posts about this grouping
    /// </summary>
    public List<BlogPost> BlogPosts { get; set; } = [];

    public override string ToString()
    {
        var sb = new StringBuilder();

        sb.AppendLine($"Id: {Id}");
        sb.AppendLine($"Artifact Grouping Identifier: {ArtifactGroupingIdentifier}");
        sb.AppendLine($"Category:");
        sb.AppendLine(Category.ToString());
        sb.AppendLine($"Title: {Title}");
        sb.AppendLine($"Description: {Description}");
        sb.AppendLine($"Type:{Type}");
        sb.AppendLine($"Publically Visible: {IsPublicallyVisible}");
        sb.AppendLine($"Artifact Entries:");
        foreach (var artifact in ChildArtifactEntries)
        {
            sb.AppendLine(artifact.ToString());
            sb.AppendLine();
        }

        return sb.ToString();
    }

    [NotMapped]
    public IEnumerable<ArtifactEntryTag> ChildTags
    {
        get
        {
            HashSet<ArtifactEntryTag> seenTags = [];
            for (int index = 0; index < ChildArtifactEntries.Count; ++index)
            {
                // Get the tags for this entry, skip if no tags 
                List<ArtifactEntryTag>? tags = ChildArtifactEntries[index].Tags;
                if (tags is null)
                {
                    continue;
                }

                // Only yield a tag if we have not yielded it yet
                foreach (ArtifactEntryTag tag in tags)
                {
                    if (seenTags.Contains(tag))
                    {
                        continue;
                    }

                    seenTags.Add(tag);
                    yield return tag;
                }
            }
        }
    }

    /// <summary>
    /// Enables searching using postgres full text search
    /// </summary>
    /// 
    public string AllSearchString { get; set; } = "";
    public NpgsqlTsVector? AllSearchVector { get; set; } 

    public string TagsSearchString { get; set; } = "";

    public NpgsqlTsVector? TagsSearchVector { get; set; } 

    public string DefectsSearchString { get; set; } = "";

    public NpgsqlTsVector? DefectsSearchVector { get; set; }

    public string ListedNamesSearchString { get; set; } = "";

    public NpgsqlTsVector? ListedNamesSearchVector { get; set; }

    public string TitleSearchString { get; set; } = "";

    public NpgsqlTsVector? TitleSearchVector { get; set; }

    public string DescriptionSearchString { get; set; } = "";

    public NpgsqlTsVector? DescriptionSearchVector { get; set; }

    public string FilenamesSearchString { get; set; } = "";
    public NpgsqlTsVector FilenamesSearchVector { get; set; }

    public string FileContentSearchString { get; set; } = "";

    public NpgsqlTsVector FileContentSearchVector { get; set; }
}
