using ZB.MOM.WW.OtOpcUa.Driver.AbLegacy;

namespace ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests;

internal class FakeAbLegacyTag : IAbLegacyTagRuntime
{
    public AbLegacyTagCreateParams CreationParams { get; }
    public object? Value { get; set; }
    public int Status { get; set; }
    public bool ThrowOnInitialize { get; set; }
    public bool ThrowOnRead { get; set; }
    public bool ThrowOnWrite { get; set; }
    public Exception? Exception { get; set; }
    public int InitializeCount { get; private set; }
    public int ReadCount { get; private set; }
    public int WriteCount { get; private set; }
    public bool Disposed { get; private set; }

    public FakeAbLegacyTag(AbLegacyTagCreateParams p) => CreationParams = p;

    public virtual Task InitializeAsync(CancellationToken ct)
    {
        InitializeCount++;
        if (ThrowOnInitialize) throw Exception ?? new InvalidOperationException();
        return Task.CompletedTask;
    }

    public virtual Task ReadAsync(CancellationToken ct)
    {
        ReadCount++;
        if (ThrowOnRead) throw Exception ?? new InvalidOperationException();
        return Task.CompletedTask;
    }

    public virtual Task WriteAsync(CancellationToken ct)
    {
        WriteCount++;
        if (ThrowOnWrite) throw Exception ?? new InvalidOperationException();
        return Task.CompletedTask;
    }

    public virtual int GetStatus() => Status;
    public virtual object? DecodeValue(AbLegacyDataType type, int? bitIndex) => Value;
    public virtual void EncodeValue(AbLegacyDataType type, int? bitIndex, object? value) => Value = value;
    public virtual void Dispose() => Disposed = true;
}

internal sealed class FakeAbLegacyTagFactory : IAbLegacyTagFactory
{
    public Dictionary<string, FakeAbLegacyTag> Tags { get; } = new(StringComparer.OrdinalIgnoreCase);
    public Func<AbLegacyTagCreateParams, FakeAbLegacyTag>? Customise { get; set; }

    public IAbLegacyTagRuntime Create(AbLegacyTagCreateParams p)
    {
        var fake = Customise?.Invoke(p) ?? new FakeAbLegacyTag(p);
        Tags[p.TagName] = fake;
        return fake;
    }
}
