using System.Text.Json.Serialization;

namespace Synor.Sdk.Storage;

/// <summary>
/// Storage network.
/// </summary>
public enum StorageNetwork
{
    [JsonPropertyName("mainnet")] Mainnet,
    [JsonPropertyName("testnet")] Testnet,
    [JsonPropertyName("devnet")] Devnet
}

/// <summary>
/// Pin status.
/// </summary>
public enum PinStatus
{
    [JsonPropertyName("queued")] Queued,
    [JsonPropertyName("pinning")] Pinning,
    [JsonPropertyName("pinned")] Pinned,
    [JsonPropertyName("failed")] Failed
}

/// <summary>
/// Storage configuration.
/// </summary>
public class StorageConfig
{
    public required string ApiKey { get; init; }
    public string Endpoint { get; init; } = "https://storage.synor.io/v1";
    public string Gateway { get; init; } = "https://gateway.synor.io";
    public StorageNetwork Network { get; init; } = StorageNetwork.Mainnet;
    public TimeSpan Timeout { get; init; } = TimeSpan.FromMinutes(5);
    public int Retries { get; init; } = 3;
    public bool Debug { get; init; } = false;
}

/// <summary>
/// Upload options.
/// </summary>
public class UploadOptions
{
    public string? Name { get; init; }
    public string? ContentType { get; init; }
    public bool Pin { get; init; } = true;
    public Dictionary<string, string>? Metadata { get; init; }
    public bool WrapWithDirectory { get; init; } = false;
}

/// <summary>
/// Upload response.
/// </summary>
public record UploadResponse(
    [property: JsonPropertyName("cid")] string Cid,
    [property: JsonPropertyName("size")] long Size,
    [property: JsonPropertyName("name")] string? Name = null,
    [property: JsonPropertyName("pinned")] bool Pinned = true
);

/// <summary>
/// Pin request.
/// </summary>
public class PinRequest
{
    public required string Cid { get; init; }
    public string? Name { get; init; }
    public Dictionary<string, string>? Metadata { get; init; }
    public string[]? Origins { get; init; }
}

/// <summary>
/// Pin information.
/// </summary>
public record Pin(
    [property: JsonPropertyName("cid")] string Cid,
    [property: JsonPropertyName("name")] string? Name,
    [property: JsonPropertyName("status")] PinStatus Status,
    [property: JsonPropertyName("size")] long Size,
    [property: JsonPropertyName("created_at")] DateTime CreatedAt,
    [property: JsonPropertyName("metadata")] Dictionary<string, string>? Metadata = null
);

/// <summary>
/// File entry for directory operations.
/// </summary>
public class FileEntry
{
    public required string Path { get; init; }
    public required byte[] Content { get; init; }
    public string? ContentType { get; init; }
}

/// <summary>
/// Directory entry.
/// </summary>
public record DirectoryEntry(
    [property: JsonPropertyName("name")] string Name,
    [property: JsonPropertyName("cid")] string Cid,
    [property: JsonPropertyName("size")] long Size,
    [property: JsonPropertyName("type")] string Type
);

/// <summary>
/// CAR file.
/// </summary>
public record CarFile(
    [property: JsonPropertyName("root_cid")] string RootCid,
    [property: JsonPropertyName("data")] byte[] Data,
    [property: JsonPropertyName("size")] long Size
);

/// <summary>
/// Storage statistics.
/// </summary>
public record StorageStats(
    [property: JsonPropertyName("total_size")] long TotalSize,
    [property: JsonPropertyName("pin_count")] int PinCount,
    [property: JsonPropertyName("bandwidth_used")] long BandwidthUsed,
    [property: JsonPropertyName("storage_limit")] long StorageLimit,
    [property: JsonPropertyName("bandwidth_limit")] long BandwidthLimit
);

/// <summary>
/// Storage exception.
/// </summary>
public class StorageException : Exception
{
    public string? Code { get; }
    public int? StatusCode { get; }

    public StorageException(string message, string? code = null, int? statusCode = null)
        : base(message)
    {
        Code = code;
        StatusCode = statusCode;
    }
}
