using RobotNet.MapShares.Dtos;

namespace RobotNet.WebApp.Maps.Models;

public class MapZoneModel : IEnumerable<ZoneModel>
{
    private readonly Dictionary<Guid, ZoneModel> dicZones = [];
    public ZoneModel this[int i] => dicZones.Values.ElementAt(i);
    public ZoneModel this[Guid id] => dicZones[id];
    public IEnumerator<ZoneModel> GetEnumerator() => dicZones.Values.GetEnumerator();
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
    public bool TryGetValue(Guid id, out ZoneModel? value) => dicZones.TryGetValue(id, out value);


    public ZoneModel? ZoneActived { get; private set; }
    public event Action? Changed;
    public event Action<ZoneModel, bool>? ActivedZoneChanged;

    public void ReplaceAll(IEnumerable<ZoneDto> zones)
    {
        foreach (var zone in dicZones.Values)
        {
            zone.ActiveChanged -= Zone_ActiveChanged;
            zone.Dispose();
            if (ZoneActived is not null && ZoneActived == zone) ZoneActived = null;
        }
        dicZones.Clear();

        foreach (var zone in zones)
        {
            var model = new ZoneModel(zone);
            model.ActiveChanged += Zone_ActiveChanged;
            dicZones.Add(zone.Id, model);
        }
        Changed?.Invoke();
    }

    public void Add(ZoneDto zone)
    {
        if (dicZones.ContainsKey(zone.Id)) return;

        var model = new ZoneModel(zone);
        dicZones.Add(model.Id, model);
        model.ActiveChanged += Zone_ActiveChanged;
        Changed?.Invoke();
    }

    public void Remove(ZoneModel zone)
    {
        if (!dicZones.ContainsKey(zone.Id)) return;

        zone.UnActive();
        zone.ActiveChanged -= Zone_ActiveChanged;
        if (ZoneActived is not null && zone.Id == ZoneActived.Id) ZoneActived = null;
        zone.Dispose();
        dicZones.Remove(zone.Id);
        Changed?.Invoke();
    }

    private void Zone_ActiveChanged(ZoneModel zone, bool state)
    {
        if (state)
        {
            if (ZoneActived is not null && ZoneActived != zone || ZoneActived is null)
            {
                ZoneActived?.UnActive();
                ZoneActived = zone;
            }
        }
        ActivedZoneChanged?.Invoke(zone, state);
    }
    public void UnActivedZone() => ZoneActived?.UnActive();
}
