using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Dpz.Core.Public.Entity;
using Dpz.Core.Public.ViewModel.RequestEvent;
using MongoDB.Driver;
using MongoDB.Driver.Linq;

namespace Dpz.Core.Service.Event;

public class CodeCompatibleHandler(
    IRepository<CodeFileSystemEntry> codeFileSystemEntryRepository,
    IRepository<CodeNote> codeNoteRepository
) : IRequestHandler<CodeCompatibleRequest>
{
    public async Task Handle(CodeCompatibleRequest request, CancellationToken cancellationToken)
    {
        if (request.NewEntries is { Count: > 0 })
        {
            await HandleIncrementalAsync(request.NewEntries, cancellationToken);
            return;
        }

        await HandleFullAsync(cancellationToken);
    }

    private async Task HandleIncrementalAsync(
        IReadOnlyCollection<CodeCompatibleEntry> newEntries,
        CancellationToken cancellationToken
    )
    {
        var pathGroups = newEntries
            .Select(x => BuildPathString(x.ParentPathSegments))
            .Where(x => !string.IsNullOrWhiteSpace(x))
            .Distinct(StringComparer.OrdinalIgnoreCase)
            .ToList();
        if (pathGroups.Count == 0)
        {
            return;
        }

        var noteFilter = Builders<CodeNote>.Filter.In(x => x.Path, pathGroups);
        var notes = await codeNoteRepository
            .SearchFor(noteFilter)
            .ToListAsync(cancellationToken);
        if (notes.Count == 0)
        {
            return;
        }

        var noteMap = notes.ToDictionary(
            x => BuildNoteKey(x.Path, x.Name),
            StringComparer.OrdinalIgnoreCase
        );

        var updateList = new List<CodeFileSystemEntry>();

        foreach (var entry in newEntries)
        {
            var key = BuildNoteKey(BuildPathString(entry.ParentPathSegments), entry.Name);
            if (!noteMap.TryGetValue(key, out var note))
            {
                continue;
            }

            var entryPathSegments = BuildPathSegments(entry.ParentPathSegments, entry.Name);
            var entryFilter = Builders<CodeFileSystemEntry>.Filter.Eq(
                x => x.PathSegments,
                entryPathSegments
            );
            var updatedEntry = await codeFileSystemEntryRepository
                .SearchFor(entryFilter)
                .FirstOrDefaultAsync(cancellationToken);
            if (updatedEntry == null)
            {
                continue;
            }

            var changed = false;
            if (string.IsNullOrWhiteSpace(updatedEntry.Description)
                && !string.IsNullOrWhiteSpace(note.Note))
            {
                updatedEntry.Description = note.Note;
                changed = true;
            }

            if (string.IsNullOrWhiteSpace(updatedEntry.AiAnalyzeResult)
                && !string.IsNullOrWhiteSpace(note.AiAnalyzeResult))
            {
                updatedEntry.AiAnalyzeResult = note.AiAnalyzeResult;
                changed = true;
            }

            if (changed)
            {
                updateList.Add(updatedEntry);
            }
        }

        if (updateList.Count > 0)
        {
            await codeFileSystemEntryRepository.UpdateAsync(updateList, cancellationToken);
        }
    }

    private async Task HandleFullAsync(CancellationToken cancellationToken)
    {
        var notes = await codeNoteRepository.SearchFor(x => true).ToListAsync(cancellationToken);
        if (notes.Count == 0)
        {
            return;
        }

        var entries = await codeFileSystemEntryRepository
            .SearchFor(x => true)
            .ToListAsync(cancellationToken);
        if (entries.Count == 0)
        {
            return;
        }

        var entryMap = entries.ToDictionary(
            x => BuildPathKey(x.PathSegments),
            StringComparer.OrdinalIgnoreCase
        );

        var updateList = new List<CodeFileSystemEntry>();

        foreach (var note in notes)
        {
            var pathSegments = BuildPathSegments(note.Path, note.Name);
            if (pathSegments.Count == 0)
            {
                continue;
            }

            var key = BuildPathKey(pathSegments);
            if (!entryMap.TryGetValue(key, out var entry))
            {
                continue;
            }

            var changed = false;
            if (
                string.IsNullOrWhiteSpace(entry.Description)
                && !string.IsNullOrWhiteSpace(note.Note)
            )
            {
                entry.Description = note.Note;
                changed = true;
            }

            if (
                string.IsNullOrWhiteSpace(entry.AiAnalyzeResult)
                && !string.IsNullOrWhiteSpace(note.AiAnalyzeResult)
            )
            {
                entry.AiAnalyzeResult = note.AiAnalyzeResult;
                changed = true;
            }

            if (changed)
            {
                updateList.Add(entry);
            }
        }

        if (updateList.Count > 0)
        {
            await codeFileSystemEntryRepository.UpdateAsync(updateList, cancellationToken);
        }
    }

    private static List<string> BuildPathSegments(string? path, string name)
    {
        var segments = new List<string>();
        if (!string.IsNullOrWhiteSpace(path))
        {
            segments.AddRange(
                path.Split(
                    '/',
                    StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries
                )
            );
        }

        if (!string.IsNullOrWhiteSpace(name))
        {
            segments.Add(name);
        }

        return segments;
    }

    private static string BuildPathKey(IEnumerable<string> segments)
    {
        return string.Join("/", segments);
    }

    private static string BuildPathString(IEnumerable<string> segments)
    {
        return string.Join("/", segments.Where(x => !string.IsNullOrWhiteSpace(x)));
    }

    private static string BuildNoteKey(string path, string name)
    {
        return string.Join("/", new[] { path, name }.Where(x => !string.IsNullOrWhiteSpace(x)));
    }

    private static List<string> BuildPathSegments(
        IEnumerable<string> parentPathSegments,
        string name
    )
    {
        var segments = parentPathSegments.Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
        if (!string.IsNullOrWhiteSpace(name))
        {
            segments.Add(name);
        }

        return segments;
    }
}
评论加载中...