using CommunityToolkit.Mvvm.ComponentModel;
using GsaEditor.Core.Models;

namespace GsaEditor.ViewModels;

/// <summary>
/// Wraps a <see cref="GsaEntry"/> for display in the details panel.
/// </summary>
public partial class EntryViewModel : ViewModelBase
{
    private readonly GsaEntry _entry;

    [ObservableProperty]
    private string _alias = string.Empty;

    [ObservableProperty]
    private bool _isCompressed;

    /// <summary>
    /// Callback invoked when entry data is modified (compression toggle, alias change).
    /// </summary>
    public Action? OnModified { get; set; }

    public EntryViewModel(GsaEntry entry)
    {
        _entry = entry;
        _alias = entry.Alias;
        _isCompressed = entry.IsCompressed;
    }

    /// <summary>
    /// The underlying <see cref="GsaEntry"/>.
    /// </summary>
    public GsaEntry Entry => _entry;

    /// <summary>
    /// Original (decompressed) file size in bytes.
    /// </summary>
    public uint OriginalSize => _entry.OriginalLength;

    /// <summary>
    /// Compressed file size in bytes.
    /// </summary>
    public uint CompressedSize => _entry.CompressedLength;

    /// <summary>
    /// Compression ratio as a percentage (0–100). Higher means more compression.
    /// </summary>
    public string CompressionRatio => OriginalSize > 0
        ? $"{(1.0 - (double)CompressedSize / OriginalSize) * 100.0:F1}%"
        : "0.0%";

    /// <summary>
    /// Human-readable original size string.
    /// </summary>
    public string OriginalSizeText => FormatSize(OriginalSize);

    /// <summary>
    /// Human-readable compressed size string.
    /// </summary>
    public string CompressedSizeText => FormatSize(CompressedSize);

    partial void OnAliasChanged(string value)
    {
        if (_entry.Alias != value)
        {
            _entry.Alias = value;
            OnModified?.Invoke();
        }
    }

    partial void OnIsCompressedChanged(bool value)
    {
        if (_entry.IsCompressed != value)
        {
            var decompressed = _entry.GetDecompressedData();
            _entry.SetData(decompressed, value);
            OnPropertyChanged(nameof(OriginalSize));
            OnPropertyChanged(nameof(CompressedSize));
            OnPropertyChanged(nameof(CompressionRatio));
            OnPropertyChanged(nameof(OriginalSizeText));
            OnPropertyChanged(nameof(CompressedSizeText));
            OnModified?.Invoke();
        }
    }

    private static string FormatSize(long bytes)
    {
        if (bytes < 1024) return $"{bytes} B";
        if (bytes < 1024 * 1024) return $"{bytes / 1024.0:F1} KB";
        return $"{bytes / (1024.0 * 1024.0):F1} MB";
    }
}
