using LightlessSync.API.Data;
using System;
using System.Collections.Generic;
using System.Linq;

namespace LightlessSync.PlayerData.Data;

public class FileReplacementDataComparer : IEqualityComparer<FileReplacementData>
{
    private static readonly FileReplacementDataComparer _instance = new();

    private FileReplacementDataComparer()
    { }

    public static FileReplacementDataComparer Instance => _instance;

    public bool Equals(FileReplacementData? x, FileReplacementData? y)
    {
        if (ReferenceEquals(x, y))
            return true;
        if (x is null || y is null)
            return false;

        return string.Equals(x.Hash, y.Hash, StringComparison.OrdinalIgnoreCase)
            && ComparePathSets(x.GamePaths, y.GamePaths)
            && string.Equals(x.FileSwapPath ?? string.Empty, y.FileSwapPath ?? string.Empty, StringComparison.Ordinal);
    }

    public int GetHashCode(FileReplacementData obj)
    {
        if (obj is null)
            return 0;

        var hash = StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Hash ?? string.Empty);
        hash = HashCode.Combine(hash, GetSetHashCode(obj.GamePaths));
        hash = HashCode.Combine(hash, StringComparer.OrdinalIgnoreCase.GetHashCode(obj.FileSwapPath ?? string.Empty));
        return hash;
    }

    private static bool ComparePathSets(IEnumerable<string> first, IEnumerable<string> second)
    {
        var left = new HashSet<string>(first ?? Enumerable.Empty<string>(), StringComparer.OrdinalIgnoreCase);
        var right = new HashSet<string>(second ?? Enumerable.Empty<string>(), StringComparer.OrdinalIgnoreCase);
        return left.SetEquals(right);
    }

    private static int GetSetHashCode(IEnumerable<string> paths)
    {
        int hash = 0;
        foreach (var element in paths ?? Enumerable.Empty<string>())
        {
            hash = unchecked(hash + StringComparer.OrdinalIgnoreCase.GetHashCode(element));
        }

        return hash;
    }
}