using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows.Data;
using System.Windows.Input;

namespace XLAB
{
    internal sealed class SelectInstrumentTypeWindowViewModel : ObservableObject
    {
        private string _searchText;
        private AvailableInstrumentItem _selectedType;
        private string _serialNumber;
        private string _statusText;

        public SelectInstrumentTypeWindowViewModel(string customerName, IReadOnlyList<AvailableInstrumentItem> instrumentTypes)
        {
            CustomerName = customerName ?? string.Empty;
            InstrumentTypes = new ObservableCollection<AvailableInstrumentItem>(instrumentTypes ?? new List<AvailableInstrumentItem>());
            InstrumentTypesView = CollectionViewSource.GetDefaultView(InstrumentTypes);
            InstrumentTypesView.Filter = FilterTypes;

            ConfirmCommand = new RelayCommand(Confirm, CanConfirm);
            CancelCommand = new RelayCommand(Cancel);
            UpdateStatus();
        }

        public event EventHandler<bool?> CloseRequested;

        public ICommand CancelCommand { get; private set; }

        public ICommand ConfirmCommand { get; private set; }

        public string CustomerName { get; private set; }

        public ObservableCollection<AvailableInstrumentItem> InstrumentTypes { get; private set; }

        public ICollectionView InstrumentTypesView { get; private set; }

        public string SearchText
        {
            get { return _searchText; }
            set
            {
                if (SetProperty(ref _searchText, value))
                {
                    InstrumentTypesView.Refresh();
                    UpdateStatus();
                }
            }
        }

        public AvailableInstrumentItem SelectedType
        {
            get { return _selectedType; }
            set
            {
                if (SetProperty(ref _selectedType, value))
                {
                    ((RelayCommand)ConfirmCommand).RaiseCanExecuteChanged();
                    UpdateStatus();
                }
            }
        }

        public string SerialNumber
        {
            get { return _serialNumber; }
            set
            {
                if (SetProperty(ref _serialNumber, value))
                {
                    ((RelayCommand)ConfirmCommand).RaiseCanExecuteChanged();
                    UpdateStatus();
                }
            }
        }

        public string StatusText
        {
            get { return _statusText; }
            private set { SetProperty(ref _statusText, value); }
        }

        public InstrumentTypeSelectionResult GetResult()
        {
            return SelectedType == null
                ? null
                : new InstrumentTypeSelectionResult
                {
                    TypeItem = SelectedType,
                    SerialNumber = string.IsNullOrWhiteSpace(SerialNumber) ? string.Empty : SerialNumber.Trim()
                };
        }

        private void Cancel(object parameter)
        {
            RaiseCloseRequested(false);
        }

        private bool CanConfirm(object parameter)
        {
            return SelectedType != null
                   && !string.IsNullOrWhiteSpace(SerialNumber);
        }

        private void Confirm(object parameter)
        {
            RaiseCloseRequested(true);
        }

        private bool FilterTypes(object item)
        {
            var instrumentType = item as AvailableInstrumentItem;
            if (instrumentType == null)
            {
                return false;
            }

            if (string.IsNullOrWhiteSpace(SearchText))
            {
                return true;
            }

            return Contains(instrumentType.RegistryNumber, SearchText)
                   || Contains(instrumentType.InstrumentName, SearchText)
                   || Contains(instrumentType.InstrumentType, SearchText)
                   || Contains(instrumentType.RangeText, SearchText)
                   || Contains(instrumentType.AccuracyText, SearchText)
                   || Contains(instrumentType.MeasurementArea, SearchText);
        }

        private static bool Contains(string source, string searchText)
        {
            return !string.IsNullOrWhiteSpace(source)
                   && source.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0;
        }

        private void RaiseCloseRequested(bool? dialogResult)
        {
            var handler = CloseRequested;
            if (handler != null)
            {
                handler(this, dialogResult);
            }
        }

        private void UpdateStatus()
        {
            var visibleCount = InstrumentTypesView.Cast<object>().Count();
            StatusText = string.Format(
                "Всего типов: {0}. По фильтру: {1}. Выбран тип: {2}. Заводской номер: {3}.",
                InstrumentTypes.Count,
                visibleCount,
                SelectedType == null ? "нет" : "да",
                string.IsNullOrWhiteSpace(SerialNumber) ? "не указан" : "указан");
        }
    }
}
