using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using API.Data;
using API.Entities.Person;
using API.Extensions;
using API.Helpers.Builders;
namespace API.Services;
public interface IPersonService
{
///
/// Adds src as an alias to dst, this is a destructive operation
///
/// Merged person
/// Remaining person
/// The entities passed as arguments **must** include all relations
///
Task MergePeopleAsync(Person src, Person dst);
///
/// Adds the alias to the person, requires that the aliases are not shared with anyone else
///
/// This method does NOT commit changes
///
///
///
Task UpdatePersonAliasesAsync(Person person, IList aliases);
}
public class PersonService(IUnitOfWork unitOfWork): IPersonService
{
public async Task MergePeopleAsync(Person src, Person dst)
{
if (dst.Id == src.Id) return;
if (string.IsNullOrWhiteSpace(dst.Description) && !string.IsNullOrWhiteSpace(src.Description))
{
dst.Description = src.Description;
}
if (dst.MalId == 0 && src.MalId != 0)
{
dst.MalId = src.MalId;
}
if (dst.AniListId == 0 && src.AniListId != 0)
{
dst.AniListId = src.AniListId;
}
if (dst.HardcoverId == null && src.HardcoverId != null)
{
dst.HardcoverId = src.HardcoverId;
}
if (dst.Asin == null && src.Asin != null)
{
dst.Asin = src.Asin;
}
if (dst.CoverImage == null && src.CoverImage != null)
{
dst.CoverImage = src.CoverImage;
}
MergeChapterPeople(dst, src);
MergeSeriesMetadataPeople(dst, src);
dst.Aliases.Add(new PersonAliasBuilder(src.Name).Build());
foreach (var alias in src.Aliases)
{
dst.Aliases.Add(alias);
}
unitOfWork.PersonRepository.Remove(src);
unitOfWork.PersonRepository.Update(dst);
await unitOfWork.CommitAsync();
}
private static void MergeChapterPeople(Person dst, Person src)
{
foreach (var chapter in src.ChapterPeople)
{
var alreadyPresent = dst.ChapterPeople
.Any(x => x.ChapterId == chapter.ChapterId && x.Role == chapter.Role);
if (alreadyPresent) continue;
dst.ChapterPeople.Add(new ChapterPeople
{
Role = chapter.Role,
ChapterId = chapter.ChapterId,
Person = dst,
KavitaPlusConnection = chapter.KavitaPlusConnection,
OrderWeight = chapter.OrderWeight,
});
}
}
private static void MergeSeriesMetadataPeople(Person dst, Person src)
{
foreach (var series in src.SeriesMetadataPeople)
{
var alreadyPresent = dst.SeriesMetadataPeople
.Any(x => x.SeriesMetadataId == series.SeriesMetadataId && x.Role == series.Role);
if (alreadyPresent) continue;
dst.SeriesMetadataPeople.Add(new SeriesMetadataPeople
{
SeriesMetadataId = series.SeriesMetadataId,
Role = series.Role,
Person = dst,
KavitaPlusConnection = series.KavitaPlusConnection,
OrderWeight = series.OrderWeight,
});
}
}
public async Task UpdatePersonAliasesAsync(Person person, IList aliases)
{
var normalizedAliases = aliases
.Select(a => a.ToNormalized())
.Where(a => !string.IsNullOrEmpty(a) && a != person.NormalizedName)
.ToList();
if (normalizedAliases.Count == 0)
{
person.Aliases = [];
return true;
}
var others = await unitOfWork.PersonRepository.GetPeopleByNames(normalizedAliases);
others = others.Where(p => p.Id != person.Id).ToList();
if (others.Count != 0) return false;
person.Aliases = aliases.Select(a => new PersonAliasBuilder(a).Build()).ToList();
return true;
}
}