using System.Text.Json;
using Health.Application.Users;

namespace Health.Infrastructure.Users;

public sealed class LocalAccountFileCleanup(string uploadsRoot) : IAccountFileCleanup
{
    private readonly string _uploadsRoot = Path.GetFullPath(uploadsRoot);

    public Task DeleteAsync(Guid userId, AccountFileReferences references, CancellationToken ct)
    {
        var fileUrls = new HashSet<string>(references.FileUrls, StringComparer.OrdinalIgnoreCase);
        foreach (var metadataJson in references.ConversationMetadataJson)
            AddMetadataUrls(fileUrls, metadataJson);

        foreach (var fileUrl in fileUrls)
        {
            ct.ThrowIfCancellationRequested();
            var localPath = ResolveLocalPath(fileUrl);
            if (localPath != null && File.Exists(localPath)) File.Delete(localPath);
        }

        ct.ThrowIfCancellationRequested();
        var userDirectory = Path.Combine(_uploadsRoot, "users", userId.ToString("N"));
        if (Directory.Exists(userDirectory)) Directory.Delete(userDirectory, recursive: true);

        return Task.CompletedTask;
    }

    private static void AddMetadataUrls(HashSet<string> fileUrls, string metadataJson)
    {
        try
        {
            using var document = JsonDocument.Parse(metadataJson);
            AddStringProperty(document.RootElement, "imageUrl", fileUrls);
            AddStringProperty(document.RootElement, "pdfUrl", fileUrls);
        }
        catch (JsonException)
        {
            // 旧消息元数据可能不是合法 JSON；不影响其余账号数据注销。
        }
    }

    private static void AddStringProperty(JsonElement root, string propertyName, HashSet<string> fileUrls)
    {
        if (root.ValueKind != JsonValueKind.Object ||
            !root.TryGetProperty(propertyName, out var property) ||
            property.ValueKind != JsonValueKind.String)
            return;

        var value = property.GetString();
        if (!string.IsNullOrWhiteSpace(value)) fileUrls.Add(value);
    }

    private string? ResolveLocalPath(string fileUrl)
    {
        var urlPath = fileUrl;
        if (Uri.TryCreate(fileUrl, UriKind.Absolute, out var absoluteUri))
            urlPath = absoluteUri.AbsolutePath;

        var uploadsIndex = urlPath.IndexOf("/uploads/", StringComparison.OrdinalIgnoreCase);
        if (uploadsIndex < 0) return null;

        string relativePath;
        try
        {
            relativePath = Uri.UnescapeDataString(urlPath[(uploadsIndex + "/uploads/".Length)..]);
        }
        catch (UriFormatException)
        {
            return null;
        }

        var queryIndex = relativePath.IndexOfAny(['?', '#']);
        if (queryIndex >= 0) relativePath = relativePath[..queryIndex];
        relativePath = relativePath.Replace('/', Path.DirectorySeparatorChar);

        var fullPath = Path.GetFullPath(Path.Combine(_uploadsRoot, relativePath));
        var rootPrefix = _uploadsRoot.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
            + Path.DirectorySeparatorChar;
        return fullPath.StartsWith(rootPrefix, StringComparison.OrdinalIgnoreCase) ? fullPath : null;
    }
}
