using AlarmInfoServerSim.Services;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Net;

namespace AlarmInfoServerSim.ViewModels;

public partial class StatusBarViewModel : ObservableObject ,IDisposable
{
    private readonly ILogService _logService; 
    private readonly ISharedConfig _sharedConfig;
    private readonly IInfoSendingService _infoSendingService;

    private bool disposedValue;

    [ObservableProperty]
    private List<IPAddress> _iPAddresses;

    [ObservableProperty]
    private bool _isSelectingEnable;

    [ObservableProperty]
    private IPAddress _selectedIP;

    [ObservableProperty]
    private int _selectedPort;

    [ObservableProperty]
    private string _buttonContent;

    [ObservableProperty]
    private string _remoteIp;

    [ObservableProperty]
    private string _remotePort;

    [ObservableProperty]
    private string _status;

    public StatusBarViewModel(ILogService logService, ISharedConfig sharedConfig, IInfoSendingService sendInfoService)
    {
        _logService = logService;
        _sharedConfig = sharedConfig;
        _infoSendingService = sendInfoService;
        _infoSendingService.TcpServerStatusChanged += OnTcpServerStatusChanged;
        _infoSendingService.ConnectionChanged += OnConnectionChanged;

        _iPAddresses = _sharedConfig.IPAddresses;
        _isSelectingEnable = true;
        _selectedIP = IPAddress.None;
        _selectedPort = 50052;
        _buttonContent = "Open";
        _remoteIp = "Unknown";
        _remotePort = "Unknown";
        _status = "Disconnected";
    }

    [RelayCommand]
    private void OpenOrClose()
    {
        if (ButtonContent == "Open")
        {
            if (SelectedIP == IPAddress.None || SelectedPort < 0)
            {
                _logService.Log($"IP or Port is not correct");
                return;
            }
            _sharedConfig.SelectedIPAddress = SelectedIP;
            _sharedConfig.SelectedPort = SelectedPort;
            _infoSendingService.Open();
            return;
        }

        if (ButtonContent == "Close")
        {
            _infoSendingService.Close();
            return;
        }
    }

    private void OnTcpServerStatusChanged(object? sender, bool e)
    {
        App.Current.Dispatcher.Invoke(() =>
        {
            ButtonContent = e ? "Close" : "Open";
            IsSelectingEnable = !e;
        });
        
    }

    private void OnConnectionChanged(object? sender, (bool, UniversalNetFrame451.IO.TcpConnection) e)
    {
        App.Current.Dispatcher.Invoke(() =>
        {
            if (e.Item1)
            {
                Status = "Connected";
                RemoteIp = e.Item2.RemoteEndPoint.Address.ToString();
                RemotePort = e.Item2.RemoteEndPoint.Port.ToString();
                _logService.Log($"Get a connection from {RemoteIp}:{RemotePort}");
            }
            else
            {
                Status = "Disconnected";
                RemoteIp = "Unknown";
                RemotePort = "Unknown";
                _logService.Log($"The connection lost");
            }
        });
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                // TODO: dispose managed state (managed objects)
                _infoSendingService.TcpServerStatusChanged-=OnTcpServerStatusChanged;
                _infoSendingService.ConnectionChanged -= OnConnectionChanged;
            }

            // TODO: free unmanaged resources (unmanaged objects) and override finalizer
            // TODO: set large fields to null
            disposedValue = true;
        }
    }

    // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
    // ~StatusBarViewModel()
    // {
    //     // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
    //     Dispose(disposing: false);
    // }

    public void Dispose()
    {
        // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }
}
