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

namespace XLAB
{
    internal sealed class PrdspvEditWindowViewModel : ObservableObject
    {
        private readonly IReadOnlyList<PrdspvDirectoryItem> _existingItems;
        private string _notes;
        private int _stampTypeId;
        private string _stampCode;
        private string _validationMessage;

        public PrdspvEditWindowViewModel(PrdspvDirectoryItem seed, bool isNew, IReadOnlyList<PrdspvDirectoryItem> existingItems, PrsnDirectoryService service)
        {
            var source = seed ?? new PrdspvDirectoryItem();
            _existingItems = existingItems ?? Array.Empty<PrdspvDirectoryItem>();
            Id = source.Id;
            EmploymentId = source.EmploymentId;
            IsNew = isNew;

            StampTypeItems = service.LoadSpvdmkReferences();
            StampTypeId = source.StampTypeId;
            StampCode = source.StampCode ?? string.Empty;
            ReceivedOn = source.ReceivedOn;
            Notes = source.Notes ?? string.Empty;

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

        public event EventHandler<bool?> CloseRequested;

        public ICommand CancelCommand { get; private set; }
        public ICommand ConfirmCommand { get; private set; }
        public int EmploymentId { get; private set; }
        public int Id { get; private set; }
        public bool IsNew { get; private set; }

        public string Notes
        {
            get { return _notes; }
            set { SetProperty(ref _notes, value); }
        }

        public DateTime? ReceivedOn { get; set; }

        public string StampCode
        {
            get { return _stampCode; }
            set { SetProperty(ref _stampCode, value); }
        }

        public int StampTypeId
        {
            get { return _stampTypeId; }
            set { SetProperty(ref _stampTypeId, value); }
        }

        public IReadOnlyList<DirectoryLookupItem> StampTypeItems { get; private set; }

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

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

        public PrdspvDirectoryItem ToResult()
        {
            return new PrdspvDirectoryItem
            {
                EmploymentId = EmploymentId,
                Id = Id,
                Notes = NormalizeNullable(Notes),
                ReceivedOn = ReceivedOn,
                StampCode = NormalizeRequired(StampCode),
                StampTypeId = StampTypeId
            };
        }

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

        private void Confirm(object parameter)
        {
            var normalizedStampCode = NormalizeRequired(StampCode);
            var normalizedNotes = NormalizeNullable(Notes);

            if (StampTypeId <= 0)
            {
                ValidationMessage = "Укажите вид клейма.";
                return;
            }

            if (normalizedStampCode.Length == 0)
            {
                ValidationMessage = "Укажите шифр клейма.";
                return;
            }

            if (normalizedStampCode.Length > PrdspvDirectoryRules.StampCodeMaxLength)
            {
                ValidationMessage = string.Format("Шифр клейма не должен превышать {0} символов.", PrdspvDirectoryRules.StampCodeMaxLength);
                return;
            }

            if (normalizedNotes != null && normalizedNotes.Length > PrdspvDirectoryRules.NotesMaxLength)
            {
                ValidationMessage = string.Format("Дополнительные сведения не должны превышать {0} символов.", PrdspvDirectoryRules.NotesMaxLength);
                return;
            }

            var duplicate = _existingItems.FirstOrDefault(delegate(PrdspvDirectoryItem item)
            {
                return item != null
                       && item.Id != Id
                       && item.StampTypeId == StampTypeId;
            });
            if (duplicate != null)
            {
                ValidationMessage = "Выбранный вид клейма уже существует у этого сотрудника.";
                return;
            }

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

        private string NormalizeNullable(string value)
        {
            return string.IsNullOrWhiteSpace(value) ? null : value.Trim();
        }

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

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