using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;

namespace XLAB2
{
    internal sealed class TpvdklWindowViewModel : ObservableObject
    {
        private readonly ITypeSizeDialogService _dialogService;
        private readonly TypeSizeDirectoryService _service;
        private bool _isBusy;
        private TpvdklDirectoryItem _selectedItem;

        public TpvdklWindowViewModel(TipsDirectoryItem tipsItem, TypeSizeDirectoryService service, ITypeSizeDialogService dialogService)
        {
            TipsItem = tipsItem;
            _service = service;
            _dialogService = dialogService;
            Items = new ObservableCollection<TpvdklDirectoryItem>();
            AddCommand = new RelayCommand(delegate { AddAsync(); }, delegate { return !IsBusy; });
            EditCommand = new RelayCommand(delegate { EditAsync(); }, delegate { return !IsBusy && SelectedItem != null; });
            DeleteCommand = new RelayCommand(delegate { DeleteAsync(); }, delegate { return !IsBusy && SelectedItem != null; });
        }

        public ICommand AddCommand { get; private set; }
        public string Caption { get { return string.Format("Виды клейм для типа СИ: {0}", TipsItem == null ? string.Empty : TipsItem.TypeName); } }
        public ICommand DeleteCommand { get; private set; }
        public ICommand EditCommand { get; private set; }
        public ObservableCollection<TpvdklDirectoryItem> Items { get; private set; }
        public TipsDirectoryItem TipsItem { get; private set; }

        public bool IsBusy
        {
            get { return _isBusy; }
            private set
            {
                if (SetProperty(ref _isBusy, value))
                {
                    ((RelayCommand)AddCommand).RaiseCanExecuteChanged();
                    ((RelayCommand)EditCommand).RaiseCanExecuteChanged();
                    ((RelayCommand)DeleteCommand).RaiseCanExecuteChanged();
                }
            }
        }

        public TpvdklDirectoryItem SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                if (SetProperty(ref _selectedItem, value))
                {
                    ((RelayCommand)EditCommand).RaiseCanExecuteChanged();
                    ((RelayCommand)DeleteCommand).RaiseCanExecuteChanged();
                }
            }
        }

        public async Task InitializeAsync()
        {
            await RefreshCoreAsync(null);
        }

        private void AddAsync()
        {
            var result = _dialogService.ShowTpvdklEditDialog(new TpvdklDirectoryItem { TipsId = TipsItem.Id }, true, Items.ToList(), _service);
            if (result == null) return;
            RunMutation(async delegate
            {
                var id = await Task.Run(delegate { return _service.AddTpvdklItem(result); });
                await RefreshCoreAsync(id);
                _dialogService.ShowInfo("Вид клейма добавлен.");
            });
        }

        private void EditAsync()
        {
            if (SelectedItem == null) return;
            var result = _dialogService.ShowTpvdklEditDialog(new TpvdklDirectoryItem { Id = SelectedItem.Id, TipsId = SelectedItem.TipsId, VerificationTypeId = SelectedItem.VerificationTypeId, StampKindId = SelectedItem.StampKindId }, false, Items.ToList(), _service);
            if (result == null) return;
            RunMutation(async delegate
            {
                await Task.Run(delegate { _service.UpdateTpvdklItem(result); });
                await RefreshCoreAsync(result.Id);
                _dialogService.ShowInfo("Вид клейма обновлён.");
            });
        }

        private void DeleteAsync()
        {
            if (SelectedItem == null) return;
            var selected = SelectedItem;
            if (!_dialogService.Confirm(string.Format("Удалить связь \"{0} / {1}\"?", selected.VerificationTypeName, selected.StampKindName))) return;
            RunMutation(async delegate
            {
                await Task.Run(delegate { _service.DeleteTpvdklItem(selected.Id); });
                await RefreshCoreAsync(null);
                _dialogService.ShowInfo("Вид клейма удалён.");
            });
        }

        private async Task RefreshCoreAsync(int? idToSelect)
        {
            try
            {
                IsBusy = true;
                var items = await Task.Run(delegate { return _service.LoadTpvdklItems(TipsItem.Id); });
                Items.Clear();
                foreach (var item in items) Items.Add(item);
                SelectedItem = idToSelect.HasValue ? Items.FirstOrDefault(delegate(TpvdklDirectoryItem item) { return item.Id == idToSelect.Value; }) : Items.FirstOrDefault();
            }
            catch (Exception ex)
            {
                _dialogService.ShowError(ex.Message);
            }
            finally
            {
                IsBusy = false;
            }
        }

        private async void RunMutation(Func<Task> operation)
        {
            try
            {
                IsBusy = true;
                await operation();
            }
            catch (InvalidOperationException ex)
            {
                _dialogService.ShowWarning(ex.Message);
            }
            catch (Exception ex)
            {
                _dialogService.ShowError(ex.Message);
            }
            finally
            {
                IsBusy = false;
            }
        }
    }
}
