using System;
using System.Collections.Generic;
using System.Text.Json;
using LiteDB;

namespace Dacryptero.Search
{
    public class SearchResult
    {
        public ObjectId Id { get; }

        public DB.DBSingleController Database { get; }

        public SearchResultType Type { get; }

        public string? Role { get; }

        public string Title { get; }

        public Func<List<(string name, string value)>> Info { get; }
        
        public List<ResultFound> Previews { get; } = new List<ResultFound>();

        public double Score { get; set; }

        public Sorting.SortInfo Sorting { get; set; }

        public SearchResult(DB.DBSingleController database, ObjectId id, SearchResultType type,
            string? role, string title, Func<List<(string name, string value)>> info
        )
        {
            Database = database;
            Id = id;
            Type = type;
            Role = role;
            Title = title;
            Info = info;
        }

        public void WriteTo(Utf8JsonWriter writer)
        {
            writer.WriteStartObject();
            writer.WriteString("id", Id.ToString());
            writer.WriteString("database", Database.Config.Name);
            writer.WriteString("type", Type.ToString());
            writer.WriteString("role", Role);
            writer.WriteString("title", Title);
            writer.WritePropertyName("sorting");
            Sorting.WriteTo(writer);
            writer.WriteStartArray("info");
            var usedInfoKeys = new HashSet<string>()
            {
                "score"
            };
            {
                writer.WriteStartObject();
                writer.WriteString("name", "score");
                writer.WriteString("value", $"{Score:#,#0.0#}");
                writer.WriteEndObject();
            }
            foreach (var (name, value) in Info())
            {
                writer.WriteStartObject();
                writer.WriteString("name", name);
                writer.WriteString("value", value);
                writer.WriteEndObject();
                usedInfoKeys.Add(name);
            }
            foreach (var entry in Sorting.Entries.Span)
            {
                if (entry.Name is null || usedInfoKeys.Contains(entry.Name))
                    continue;
                usedInfoKeys.Add(entry.Name);
                writer.WriteStartObject();
                writer.WriteString("name", entry.Name);
                if (entry.StringValue is not null)
                {
                    if (entry.StringValue.Length <= 16)
                        writer.WriteString("value", entry.StringValue);
                    else writer.WriteString("value",
                        $"{entry.StringValue.Substring(0, 13)}..."
                    );
                }
                else if (entry.DoubleValue is not null)
                {
                    writer.WriteString("value", entry.DoubleValue.Value.ToString());
                }
                else
                {
                    writer.WriteString("value", "unknown");
                }
                writer.WriteEndObject();
            }
            writer.WriteEndArray();
            writer.WriteStartArray("found");
            foreach (var found in Previews)
                found.WriteTo(writer);
            writer.WriteEndArray();
            writer.WriteEndObject();
        }
    }
}