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

namespace XLAB
{
    internal sealed class SpoiEditWindowViewModel : ObservableObject
    {
        private readonly IReadOnlyList<SpoiDirectoryItem> _existingItems;
        private string _code;
        private string _name;
        private string _validationMessage;

        public SpoiEditWindowViewModel(SpoiDirectoryItem seed, bool isNew, IReadOnlyList<SpoiDirectoryItem> existingItems)
        {
            var source = seed ?? new SpoiDirectoryItem();
            _existingItems = existingItems ?? Array.Empty<SpoiDirectoryItem>();
            Id = source.Id;
            IsNew = isNew;
            Code = source.Code ?? string.Empty;
            Name = source.Name ?? string.Empty;

            ConfirmCommand = new RelayCommand(Confirm);
            CancelCommand = new RelayCommand(Cancel);
        }

        public event EventHandler<bool?> CloseRequested;

        public ICommand CancelCommand { get; private set; }

        public string Code
        {
            get { return _code; }
            set { SetProperty(ref _code, value); }
        }

        public ICommand ConfirmCommand { get; private set; }

        public int Id { get; private set; }

        public bool IsNew { get; private set; }

        public string Name
        {
            get { return _name; }
            set { SetProperty(ref _name, value); }
        }

        public string Title
        {
            get { return IsNew ? "Новая область измерений" : "Редактирование области измерений"; }
        }

        public string ValidationMessage
        {
            get { return _validationMessage; }
            private set { SetProperty(ref _validationMessage, value); }
        }

        public SpoiDirectoryItem ToResult()
        {
            return new SpoiDirectoryItem
            {
                Id = Id,
                Code = string.IsNullOrWhiteSpace(Code) ? string.Empty : Code.Trim(),
                Name = string.IsNullOrWhiteSpace(Name) ? string.Empty : Name.Trim()
            };
        }

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

        private void Confirm(object parameter)
        {
            var normalizedCode = string.IsNullOrWhiteSpace(Code) ? string.Empty : Code.Trim();
            var normalizedName = string.IsNullOrWhiteSpace(Name) ? string.Empty : Name.Trim();

            if (normalizedCode.Length == 0)
            {
                ValidationMessage = "Укажите код ОИ.";
                return;
            }

            if (normalizedCode.Length > SpoiDirectoryRules.CodeMaxLength)
            {
                ValidationMessage = string.Format("Код ОИ не должен превышать {0} символов.", SpoiDirectoryRules.CodeMaxLength);
                return;
            }

            if (normalizedName.Length == 0)
            {
                ValidationMessage = "Укажите область измерений.";
                return;
            }

            if (normalizedName.Length > SpoiDirectoryRules.NameMaxLength)
            {
                ValidationMessage = string.Format("Область измерений не должна превышать {0} символов.", SpoiDirectoryRules.NameMaxLength);
                return;
            }

            var duplicateCode = _existingItems.FirstOrDefault(delegate(SpoiDirectoryItem item)
            {
                return item != null
                       && item.Id != Id
                       && string.Equals(
                           string.IsNullOrWhiteSpace(item.Code) ? string.Empty : item.Code.Trim(),
                           normalizedCode,
                           StringComparison.OrdinalIgnoreCase);
            });
            if (duplicateCode != null)
            {
                ValidationMessage = string.Format("Код ОИ \"{0}\" уже существует в справочнике.", normalizedCode);
                return;
            }

            var duplicateName = _existingItems.FirstOrDefault(delegate(SpoiDirectoryItem item)
            {
                return item != null
                       && item.Id != Id
                       && string.Equals(
                           string.IsNullOrWhiteSpace(item.Name) ? string.Empty : item.Name.Trim(),
                           normalizedName,
                           StringComparison.OrdinalIgnoreCase);
            });
            if (duplicateName != null)
            {
                ValidationMessage = string.Format("Область измерений \"{0}\" уже существует в справочнике.", normalizedName);
                return;
            }

            ValidationMessage = string.Empty;
            RaiseCloseRequested(true);
        }

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