using System.Collections.Concurrent;
using adas_core.Domain.Enums;
using adas_core.Domain.Models.MongoModels;
using adas_core.module.Relays.Models;
using Timer = System.Timers.Timer;

namespace adas_core.module.Relays.Devices;

public abstract class RelayDevice
{
    private readonly ConcurrentDictionary<int, RelayEnum.Status> _relaysStatus = new();
    private readonly Timer? _timer;
    public readonly Relay Relay;
    public readonly RelaySettings RelaySettings;

    //string host, int port, int relays, int? refreshTime, EventHandler refreshEvent 
    protected RelayDevice(Relay relay, RelaySettings relaySettings)
    {
        Relay = relay;
        RelaySettings = relaySettings;
        if (relaySettings.RefreshTime is > 0)
        {
            _timer = new Timer();
            _timer.Interval = relaySettings.RefreshTime.Value * 1000;
            _timer.Elapsed += delegate
            {
                _timer.Stop();
                CheckStatus();
                _timer.Start();
            };
            _timer.Start();
        }
    }

    public event EventHandler<int>? RelayStatusChanged;

    public abstract bool CheckDevice();
    public abstract void CheckStatus();
    public abstract bool GetStatusRelay();

    public abstract Task<bool> GetStatusRelayAsync();

    public virtual RelayEnum.Status GetStatusRelay(int outletId)
    {
        lock (_relaysStatus)
        {
            return _relaysStatus.GetValueOrDefault(outletId, RelayEnum.Status.Unknown);
        }
    }

    public virtual void SetStatusRelay(int outletId, RelayEnum.Status status)
    {
        lock (_relaysStatus)
        {
            if (!_relaysStatus.ContainsKey(outletId) || _relaysStatus[outletId] != status)
                RelayStatusChanged?.Invoke(this, outletId);
            _relaysStatus[outletId] = status;
        }
    }

    public virtual void PowerOnOffRelay(int outletId, int milliseconds)
    {
        Task.Run(() =>
        {
            PowerOffRelay(outletId);
            Task.Delay(milliseconds);
            PowerOnRelay(outletId);
        });
    }

    public virtual void Refresh()
    {
    }

    public abstract void PowerOnRelay(int outletId);

    public abstract void PowerOffRelay(int outletId);

    public abstract void PowerOnAll();

    public abstract void PowerOffAll();

    public abstract void RebootOutlet(int outletId);

    public abstract void Reboot();
}