#nullable enable
using Baya.Application.Contracts.Common;
using Microsoft.Extensions.Options;

namespace Baya.Infrastructure.CrossCutting.Seams;

/// <summary>
/// Local-disk implementation of <see cref="IObjectStorage"/> — the mock seam. Blobs are stored as
/// files under a configured scratch root, keyed by an opaque storage key. The real implementation
/// swaps to MinIO/S3/ArvanCloud (presigned URLs) behind the same interface.
/// </summary>
public sealed class LocalDiskObjectStorage : IObjectStorage
{
    private readonly string _root;

    public LocalDiskObjectStorage(IOptions<SeamOptions> options)
    {
        var configured = options.Value.ObjectStorage.RootPath;
        _root = string.IsNullOrWhiteSpace(configured)
            ? Path.Combine(Path.GetTempPath(), "balinyaar-object-storage")
            : configured;

        Directory.CreateDirectory(_root);
    }

    public async ValueTask PutAsync(string key, Stream content, string contentType, CancellationToken cancellationToken = default)
    {
        var path = ResolvePath(key);
        Directory.CreateDirectory(Path.GetDirectoryName(path)!);

        await using var file = File.Create(path);
        await content.CopyToAsync(file, cancellationToken);
    }

    public ValueTask<Stream?> GetAsync(string key, CancellationToken cancellationToken = default)
    {
        var path = ResolvePath(key);
        Stream? stream = File.Exists(path) ? File.OpenRead(path) : null;
        return ValueTask.FromResult(stream);
    }

    public ValueTask DeleteAsync(string key, CancellationToken cancellationToken = default)
    {
        var path = ResolvePath(key);
        if (File.Exists(path))
            File.Delete(path);

        return ValueTask.CompletedTask;
    }

    public string GetUrl(string key) => new Uri(Path.Combine(_root, SanitizeKey(key))).AbsoluteUri;

    private string ResolvePath(string key) => Path.Combine(_root, SanitizeKey(key));

    // Keep the key from escaping the storage root; treat '/' as a folder separator only.
    private static string SanitizeKey(string key)
    {
        var normalized = key.Replace('\\', '/').TrimStart('/');
        var segments = normalized.Split('/', StringSplitOptions.RemoveEmptyEntries)
            .Where(s => s != "." && s != "..");
        return Path.Combine([.. segments]);
    }
}
