using Health.Domain.Entities;

namespace Health.Application.HealthArchives;

public sealed class HealthArchiveService(IHealthArchiveRepository archives) : IHealthArchiveService
{
    private readonly IHealthArchiveRepository _archives = archives;

    public async Task<HealthArchiveDto?> GetAsync(Guid userId, CancellationToken ct)
    {
        var archive = await _archives.GetByUserIdAsync(userId, ct);
        return archive == null ? null : ToDto(archive);
    }

    public async Task<HealthArchiveDto> GetOrCreateAsync(Guid userId, CancellationToken ct)
    {
        var archive = await GetOrCreateEntityAsync(userId, ct);
        await _archives.SaveChangesAsync(ct);
        return ToDto(archive);
    }

    public async Task<HealthArchiveDto> UpdateAsync(Guid userId, HealthArchiveUpdateRequest request, CancellationToken ct)
    {
        var archive = await GetOrCreateEntityAsync(userId, ct);
        Apply(archive, request);
        archive.UpdatedAt = DateTime.UtcNow;
        await _archives.SaveChangesAsync(ct);
        return ToDto(archive);
    }

    public async Task<object> ExecuteAiActionAsync(Guid userId, string action, HealthArchiveUpdateRequest request, CancellationToken ct)
    {
        if (action == "query")
        {
            var archive = await GetAsync(userId, ct);
            return archive == null ? new { found = false } : ToAiResult(archive);
        }

        var current = await GetOrCreateEntityAsync(userId, ct);
        var scopedRequest = action switch
        {
            "update_diagnosis" => request with
            {
                SurgeryType = null, SurgeryDate = null, Allergies = null,
                DietRestrictions = null, ChronicDiseases = null, FamilyHistory = null,
                Surgeries = null
            },
            "update_surgery" => request with
            {
                Diagnosis = null, Allergies = null, DietRestrictions = null,
                ChronicDiseases = null, FamilyHistory = null
            },
            "update_allergies" => new HealthArchiveUpdateRequest(null, null, null, request.Allergies, null, null, null),
            "update_chronic_diseases" => new HealthArchiveUpdateRequest(null, null, null, null, null, request.ChronicDiseases, null),
            "update_diet_restrictions" => new HealthArchiveUpdateRequest(null, null, null, null, request.DietRestrictions, null, null),
            _ => null
        };

        if (scopedRequest == null)
            return new { success = false, message = $"未知档案操作: {action}" };

        Apply(current, scopedRequest);
        current.UpdatedAt = DateTime.UtcNow;
        await _archives.SaveChangesAsync(ct);
        return new { success = true };
    }

    private async Task<HealthArchive> GetOrCreateEntityAsync(Guid userId, CancellationToken ct)
    {
        var archive = await _archives.GetByUserIdAsync(userId, ct);
        if (archive != null) return archive;

        archive = new HealthArchive { Id = Guid.NewGuid(), UserId = userId, UpdatedAt = DateTime.UtcNow };
        await _archives.AddAsync(archive, ct);
        return archive;
    }

    private static void Apply(HealthArchive archive, HealthArchiveUpdateRequest request)
    {
        if (request.Diagnosis != null) archive.Diagnosis = request.Diagnosis;
        if (request.Surgeries != null)
        {
            archive.Surgeries.Clear();
            var items = request.Surgeries
                .Where(s => !string.IsNullOrWhiteSpace(s.Type))
                .Select((s, index) => new HealthArchiveSurgery
                {
                    Id = Guid.NewGuid(),
                    HealthArchiveId = archive.Id,
                    Type = s.Type.Trim(),
                    Date = s.Date,
                    SortOrder = index,
                })
                .ToList();
            foreach (var item in items) archive.Surgeries.Add(item);
            SyncLegacySurgeryFields(archive);
        }
        else if (request.SurgeryType != null)
        {
            SeedLegacySurgeryIfNeeded(archive);
            var type = request.SurgeryType.Trim();
            if (type.Length > 0 && !archive.Surgeries.Any(s =>
                    s.Type == type && s.Date == request.SurgeryDate))
            {
                archive.Surgeries.Add(new HealthArchiveSurgery
                {
                    Id = Guid.NewGuid(),
                    HealthArchiveId = archive.Id,
                    Type = type,
                    Date = request.SurgeryDate,
                    SortOrder = archive.Surgeries.Count,
                });
            }
            SyncLegacySurgeryFields(archive);
        }
        if (request.Allergies != null) archive.Allergies = request.Allergies.ToList();
        if (request.DietRestrictions != null) archive.DietRestrictions = request.DietRestrictions.ToList();
        if (request.ChronicDiseases != null) archive.ChronicDiseases = request.ChronicDiseases.ToList();
        if (request.FamilyHistory != null) archive.FamilyHistory = request.FamilyHistory;
    }

    private static object ToAiResult(HealthArchiveDto archive) => new
    {
        found = true,
        archive.Diagnosis,
        archive.SurgeryType,
        SurgeryDate = archive.SurgeryDate?.ToString("yyyy-MM-dd"),
        surgeries = archive.Surgeries.Select(s => new { s.Type, date = s.Date?.ToString("yyyy-MM-dd") }),
        archive.Allergies,
        archive.DietRestrictions,
        archive.ChronicDiseases,
        archive.FamilyHistory,
    };

    private static HealthArchiveDto ToDto(HealthArchive archive) => new(
        archive.Id,
        archive.UserId,
        archive.Diagnosis,
        archive.SurgeryType,
        archive.SurgeryDate,
        GetSurgeries(archive),
        archive.Allergies,
        archive.DietRestrictions,
        archive.ChronicDiseases,
        archive.FamilyHistory,
        archive.UpdatedAt);

    private static IReadOnlyList<HealthArchiveSurgeryDto> GetSurgeries(HealthArchive archive)
    {
        var surgeries = archive.Surgeries
            .OrderBy(s => s.SortOrder)
            .Select(s => new HealthArchiveSurgeryDto(s.Id, s.Type, s.Date))
            .ToList();
        if (surgeries.Count == 0 && !string.IsNullOrWhiteSpace(archive.SurgeryType))
            surgeries.Add(new HealthArchiveSurgeryDto(Guid.Empty, archive.SurgeryType, archive.SurgeryDate));
        return surgeries;
    }

    private static void SyncLegacySurgeryFields(HealthArchive archive)
    {
        var first = archive.Surgeries.OrderBy(s => s.SortOrder).FirstOrDefault();
        archive.SurgeryType = first?.Type;
        archive.SurgeryDate = first?.Date;
    }

    private static void SeedLegacySurgeryIfNeeded(HealthArchive archive)
    {
        if (archive.Surgeries.Count > 0 || string.IsNullOrWhiteSpace(archive.SurgeryType)) return;
        archive.Surgeries.Add(new HealthArchiveSurgery
        {
            Id = Guid.NewGuid(),
            HealthArchiveId = archive.Id,
            Type = archive.SurgeryType,
            Date = archive.SurgeryDate,
            SortOrder = 0,
        });
    }
}
