using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;

namespace XLAB
{
    internal sealed class TprzEditWindowViewModel : ObservableObject
    {
        private readonly IReadOnlyList<TprzDirectoryItem> _existingItems;
        private string _accuracyText;
        private int _completenessId;
        private string _rangeText;
        private string _registryTypeSizeNumber;
        private string _serviceCode;
        private string _validationMessage;

        public TprzEditWindowViewModel(TprzDirectoryItem seed, bool isNew, IReadOnlyList<TprzDirectoryItem> existingItems, TypeSizeDirectoryService service)
        {
            var source = seed ?? new TprzDirectoryItem();
            _existingItems = existingItems ?? Array.Empty<TprzDirectoryItem>();
            Id = source.Id;
            TipsId = source.TipsId;
            IsNew = isNew;
            CompletenessItems = new[] { new DirectoryLookupItem { Id = 0, Name = string.Empty } }.Concat(service.LoadSpkmmkReferences()).ToList();
            RangeText = source.RangeText ?? string.Empty;
            AccuracyText = source.AccuracyText ?? string.Empty;
            CompletenessId = source.CompletenessId ?? 0;
            RegistryTypeSizeNumber = source.RegistryTypeSizeNumber ?? string.Empty;
            ServiceCode = source.ServiceCode ?? string.Empty;
            ConfirmCommand = new RelayCommand(Confirm);
            CancelCommand = new RelayCommand(Cancel);
        }

        public event EventHandler<bool?> CloseRequested;
        public ICommand CancelCommand { get; private set; }
        public IReadOnlyList<DirectoryLookupItem> CompletenessItems { get; private set; }
        public ICommand ConfirmCommand { get; private set; }
        public int Id { get; private set; }
        public bool IsNew { get; private set; }
        public int TipsId { get; private set; }
        public int CompletenessId { get { return _completenessId; } set { SetProperty(ref _completenessId, value); } }
        public string RangeText { get { return _rangeText; } set { SetProperty(ref _rangeText, value); } }
        public string AccuracyText { get { return _accuracyText; } set { SetProperty(ref _accuracyText, value); } }
        public string RegistryTypeSizeNumber { get { return _registryTypeSizeNumber; } set { SetProperty(ref _registryTypeSizeNumber, value); } }
        public string ServiceCode { get { return _serviceCode; } set { SetProperty(ref _serviceCode, value); } }
        public string Title { get { return IsNew ? "Новый типоразмер" : "Редактирование типоразмера"; } }
        public string ValidationMessage { get { return _validationMessage; } private set { SetProperty(ref _validationMessage, value); } }

        public TprzDirectoryItem ToResult()
        {
            return new TprzDirectoryItem
            {
                Id = Id,
                TipsId = TipsId,
                CompletenessId = CompletenessId > 0 ? (int?)CompletenessId : null,
                RangeText = Normalize(RangeText),
                AccuracyText = Normalize(AccuracyText),
                RegistryTypeSizeNumber = Normalize(RegistryTypeSizeNumber),
                ServiceCode = Normalize(ServiceCode)
            };
        }

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

        private void Confirm(object parameter)
        {
            var range = Normalize(RangeText);
            var accuracy = Normalize(AccuracyText);
            if (string.IsNullOrWhiteSpace(range)) { ValidationMessage = "Укажите диапазон."; return; }
            if (range.Length > TprzDirectoryRules.RangeTextMaxLength) { ValidationMessage = string.Format("Диапазон не должен превышать {0} символов.", TprzDirectoryRules.RangeTextMaxLength); return; }
            if (string.IsNullOrWhiteSpace(accuracy)) { ValidationMessage = "Укажите характеристику точности."; return; }
            if (accuracy.Length > TprzDirectoryRules.AccuracyTextMaxLength) { ValidationMessage = string.Format("Характеристика точности не должна превышать {0} символов.", TprzDirectoryRules.AccuracyTextMaxLength); return; }
            var registry = Normalize(RegistryTypeSizeNumber);
            if (!string.IsNullOrWhiteSpace(registry) && registry.Length > TprzDirectoryRules.RegistryTypeSizeNumberMaxLength) { ValidationMessage = string.Format("Номер по Госреестру не должен превышать {0} символов.", TprzDirectoryRules.RegistryTypeSizeNumberMaxLength); return; }
            var serviceCode = Normalize(ServiceCode);
            if (!string.IsNullOrWhiteSpace(serviceCode) && serviceCode.Length > TprzDirectoryRules.ServiceCodeMaxLength) { ValidationMessage = string.Format("Служебный код не должен превышать {0} символов.", TprzDirectoryRules.ServiceCodeMaxLength); return; }
            var duplicate = _existingItems.FirstOrDefault(delegate(TprzDirectoryItem item) { return item != null && item.Id != Id && string.Equals(Normalize(item.RangeText), range, StringComparison.OrdinalIgnoreCase) && string.Equals(Normalize(item.AccuracyText), accuracy, StringComparison.OrdinalIgnoreCase); });
            if (duplicate != null) { ValidationMessage = string.Format("Типоразмер с диапазоном \"{0}\" и характеристикой точности \"{1}\" уже существует.", range, accuracy); return; }
            ValidationMessage = string.Empty;
            RaiseCloseRequested(true);
        }

        private static string Normalize(string value) { return string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim(); }

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