using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VINlib;

namespace SASDesktop.ViewModels.Transport
{
    class Create : BindableBase
    {
        #region VIN
        private string _vin;
        public string VIN
        {
            get { return _vin; }
            set
            {
                _vin = value;

                if (VINlib.VinInfo.CheckVIN(value))
                {
                    // Если VIN-номер - правильный, то подставляем год
                    int year = VINlib.VinInfo.GetTransportYear(value);
                    if (year != 0)
                    {
                        // Библиотека смогла вернуть год
                        ReleaseYear = year.ToString();
                    }
                }

                RaisePropertyChanged(nameof(VIN));
            }
        }
        #endregion

        #region Производитель
        // Выбранный производитель
        private Models.Brand _selectedBrand;
        public Models.Brand SelectedBrand
        {
            get { return _selectedBrand; }
            set {
                _selectedBrand = value;
                
                // очистка модели т.к. модель зависит от производителя
                SelectedModel = null;
                ModelSearch = "";
                
                RaisePropertyChanged(nameof(SelectedBrand));
                RaisePropertyChanged(nameof(BrandIsSelected));
            }
        }
        // Предлагаемые производители
        private List<Models.Brand> _suggestedBrands;
        public List<Models.Brand> SuggestedBrands
        {
            get { return _suggestedBrands; }
            set { _suggestedBrands = value; RaisePropertyChanged(nameof(SuggestedBrands)); }
        }
        // Поиск производителя по имени
        private string _brandSearch;
        public string BrandSearch
        {
            get => _brandSearch;
            set
            {
                _brandSearch = value;
                // При наборе текста сбрасываем выбранное значение
                SelectedBrand = null;
                if (BrandSuggestionsVisible)
                {
                    UpdateBrandSuggestions();
                }
                RaisePropertyChanged(nameof(BrandSearch));
            }
        }
        // Должны ли быть видны подсказки?
        private bool _brandSuggestionsVisible;
        public bool BrandSuggestionsVisible 
        {
            get { return _brandSuggestionsVisible; }
            set 
            { 
                _brandSuggestionsVisible = value;
                if (value == true)
                {
                    UpdateBrandSuggestions();
                }
                RaisePropertyChanged(nameof(BrandSuggestionsVisible));
            }
        }
        public bool BrandIsSelected
        {
            get
            {
                return _selectedBrand != null;
            }
            set
            {
                
            }
        }
        #endregion

        #region Модель
        // Выбранное значение
        private Models.Model _selectedModel;
        public Models.Model SelectedModel
        {
            get { return _selectedModel; }
            set
            {
                _selectedModel = value;
                RaisePropertyChanged(nameof(SelectedModel));
                RaisePropertyChanged(nameof(ModelIsSelected));
            }
        }
        // Предлагаемые производители
        private List<Models.Model> _suggestedModels;
        public List<Models.Model> SuggestedModels
        {
            get { return _suggestedModels; }
            set { _suggestedModels = value; RaisePropertyChanged(nameof(SuggestedModels)); }
        }
        // Поиск производителя по имени
        private string _modelSearch;
        public string ModelSearch
        {
            get => _modelSearch;
            set
            {
                _modelSearch = value;
                // При наборе текста сбрасываем выбранное значение
                SelectedModel = null;
                if (ModelSuggestionsVisible)
                {
                    UpdateModelsSuggestions();
                }
                RaisePropertyChanged(nameof(ModelSearch));
            }
        }
        // Должны ли быть видны подсказки?
        private bool _modelSuggestionsVisible;
        public bool ModelSuggestionsVisible
        {
            get { return _modelSuggestionsVisible; }
            set
            {
                _modelSuggestionsVisible = value;
                if (value == true)
                {
                    UpdateModelsSuggestions();
                }
                RaisePropertyChanged(nameof(ModelSuggestionsVisible));
            }
        }
        public bool ModelIsSelected
        {
            get
            {
                return _selectedModel != null;
            }
            set {}
        }
        #endregion

        #region Цвет
        // Выбранное значение
        private Models.Color _selectedColor;
        public Models.Color SelectedColor
        {
            get { return _selectedColor; }
            set
            {
                _selectedColor = value;
                RaisePropertyChanged(nameof(SelectedColor));
                RaisePropertyChanged(nameof(ColorIsSelected));
            }
        }
        // Предлагаемые производители
        private List<Models.Color> _suggestedColors;
        public List<Models.Color> SuggestedColors
        {
            get { return _suggestedColors; }
            set { _suggestedColors = value; RaisePropertyChanged(nameof(SuggestedColors)); }
        }
        // Поиск производителя по имени
        private string _colorSearch;
        public string ColorSearch
        {
            get => _colorSearch;
            set
            {
                _colorSearch = value;
                // При наборе текста сбрасываем выбранное значение
                SelectedColor = null;
                if (ColorSuggestionsVisible)
                {
                    UpdateColorsSuggestions();
                }
                RaisePropertyChanged(nameof(ColorSearch));
            }
        }
        // Должны ли быть видны подсказки?
        private bool _colorSuggestionsVisible;
        public bool ColorSuggestionsVisible
        {
            get { return _colorSuggestionsVisible; }
            set
            {
                _colorSuggestionsVisible = value;
                if (value == true)
                {
                    UpdateColorsSuggestions();
                }
                RaisePropertyChanged(nameof(ColorSuggestionsVisible));
            }
        }
        public bool ColorIsSelected
        {
            get
            {
                return _selectedColor != null;
            }
            set { }
        }
        #endregion

        #region Владелец
        // Выбранное значение
        private Models.Citizen _selectedOwner;
        public Models.Citizen SelectedOwner
        {
            get { return _selectedOwner; }
            set
            {
                _selectedOwner = value;
                RaisePropertyChanged(nameof(SelectedOwner));
                RaisePropertyChanged(nameof(OwnerIsSelected));
            }
        }
        // Предлагаемые значения
        private List<Models.Citizen> _suggestedOwners;
        public List<Models.Citizen> SuggestedOwners
        {
            get { return _suggestedOwners; }
            set { _suggestedOwners = value; RaisePropertyChanged(nameof(SuggestedOwners)); }
        }
        // Поиск производителя по имени
        private string _ownerSearch;
        public string OwnerSearch
        {
            get => _ownerSearch;
            set
            {
                _ownerSearch = value;
                // При наборе текста сбрасываем выбранное значение
                SelectedColor = null;
                if (OwnerSuggestionsVisible)
                {
                    UpdateOwnerSuggestions();
                }
                RaisePropertyChanged(nameof(OwnerSearch));
            }
        }
        // Должны ли быть видны подсказки?
        private bool _ownerSuggestionsVisible;
        public bool OwnerSuggestionsVisible
        {
            get { return _ownerSuggestionsVisible; }
            set
            {
                _ownerSuggestionsVisible = value;
                if (value == true)
                {
                    UpdateOwnerSuggestions();
                }
                RaisePropertyChanged(nameof(OwnerSuggestionsVisible));
            }
        }
        public bool OwnerIsSelected
        {
            get
            {
                return _selectedOwner != null;
            }
            set { }
        }
        #endregion

        #region Категории
        public Models.Category SelectedCategory { get; set; }
        public List<Models.Category> AllCategories { get; set; }
        #endregion

        #region Год выпуска
        public string ReleaseYear { get; set; }
        #endregion

        #region Номер двигателя
        public string EngineNumber { get; set; }
        #endregion

        #region Вес
        public string Weight { get; set; }
        public string MaxLoad { get; set; }
        #endregion

        #region Модель двигателя
        // Выбранное значение
        private Models.EngineModel _selectedEngineModel;
        public Models.EngineModel SelectedEngineModel
        {
            get { return _selectedEngineModel; }
            set
            {
                _selectedEngineModel = value;
                RaisePropertyChanged(nameof(SelectedEngineModel));
                RaisePropertyChanged(nameof(EngineModelIsSelected));
            }
        }
        // Предлагаемые производители
        private List<Models.EngineModel> _suggestedEngineModels;
        public List<Models.EngineModel> SuggestedEngineModels
        {
            get { return _suggestedEngineModels; }
            set { _suggestedEngineModels = value; RaisePropertyChanged(nameof(SuggestedEngineModels)); }
        }
        // Поиск производителя по имени
        private string _engineModelSearch;
        public string EngineModelSearch
        {
            get => _engineModelSearch;
            set
            {
                _engineModelSearch = value;
                // При наборе текста сбрасываем выбранное значение
                SelectedEngineModel = null;
                if (EngineModelSuggestionsVisible)
                {
                    UpdateEngineModelSuggestions();
                }
                RaisePropertyChanged(nameof(EngineModelSearch));
            }
        }
        // Должны ли быть видны подсказки?
        private bool _engineModelSuggestionsVisible;
        public bool EngineModelSuggestionsVisible
        {
            get { return _engineModelSuggestionsVisible; }
            set
            {
                _engineModelSuggestionsVisible = value;
                if (value == true)
                {
                    UpdateEngineModelSuggestions();
                }
                RaisePropertyChanged(nameof(EngineModelSuggestionsVisible));
            }
        }
        public bool EngineModelIsSelected
        {
            get
            {
                return _selectedEngineModel != null;
            }
            set { }
        }
        #endregion


        #region Тип привода
        public Models.DriveType SelectedDrive { get; set; }
        public List<Models.DriveType> AllDriveTypes { get; set; }
        #endregion

        #region Тип ТС
        public Models.TransportType SelectedTransportType { get; set; }
        public List<Models.TransportType> AllTransportTypes { get; set; }
        #endregion

        #region Комментарий
        public string Comment { get; set; }
        #endregion

        public DelegateCommand CancelCmd { get; set; }
        public DelegateCommand SubmitCmd { get; set; }

        public Create() 
        {
            var db = new Models.SASEntities();

            _selectedBrand = null;
            _selectedModel = null;
            SelectedCategory = null;
            SelectedEngineModel = null;
            SelectedDrive = null;
            SelectedTransportType = null;

            _suggestedBrands = new List<Models.Brand>();
            _suggestedModels = new List<Models.Model>();
            AllCategories = new List<Models.Category>(db.Categories);
            AllDriveTypes = new List<Models.DriveType>(db.DriveTypes);
            AllTransportTypes = new List<Models.TransportType>(db.TransportTypes);

            CancelCmd = new DelegateCommand(CancelExecuted);
            SubmitCmd = new DelegateCommand(SubmitExecuted);
        }

        /// <summary>
        /// Обновляет подсказки производителей
        /// </summary>
        private void UpdateBrandSuggestions()
        {
            var db = new Models.SASEntities();
            if (string.IsNullOrWhiteSpace(_brandSearch))
            {
                // Если _brandSearch - пустая строка, то в список попадают все сущности
                SuggestedBrands = new List<Models.Brand>(db.Brands);
            }
            else
            {
                SuggestedBrands = new List<Models.Brand>(
                    db.Brands.Where(b => b.Name.ToLower().Contains(_brandSearch.ToLower()))
                );
            }
        }

        /// <summary>
        /// Обновляет подсказки моделей авто
        /// </summary>
        private void UpdateModelsSuggestions()
        {
            var db = new Models.SASEntities();
            if (SelectedBrand == null)
            {
                // Пустой список
                SuggestedModels = new List<Models.Model>();
                return;
            }
            
            var output = db.Models.Where(m => m.Brand == SelectedBrand.ID);
            
            if (!string.IsNullOrWhiteSpace(_modelSearch))
            {
                // Если _brandSearch - пустая строка, то в список попадают все сущности
                // связанные с _selectedBrand
                output = output.Where(m => m.Name.ToLower().Contains(_modelSearch.ToLower()));
            }

            SuggestedModels = new List<Models.Model>(output);
        }

        /// <summary>
        /// Обновляет подсказки цветов авто
        /// </summary>
        private void UpdateColorsSuggestions()
        {
            var db = new Models.SASEntities();

            if (string.IsNullOrWhiteSpace(_colorSearch))
            {
                SuggestedColors = new List<Models.Color>(db.Colors);
            }
            else
            {
                SuggestedColors = new List<Models.Color>(
                    db.Colors.Where(c =>
                        c.NameRus.ToLower().Contains(_colorSearch.ToLower()) 
                        || c.HEX.ToLower().Contains(_colorSearch.ToLower())
                        || c.NameEng.ToLower().Contains(_colorSearch.ToLower())
                    )
                );
            }
        }

        /// <summary>
        /// Обновляет подсказки владельцев
        /// </summary>
        private void UpdateOwnerSuggestions()
        {
            var db = new Models.SASEntities();
            const int maxResults = 30;

            if (string.IsNullOrWhiteSpace(_ownerSearch))
            {
                SuggestedOwners = new List<Models.Citizen>(db.Citizens.Take(maxResults));
            }
            else
            {
                SuggestedOwners = new List<Models.Citizen>(
                    db.Citizens.Where(c =>
                        c.Name.ToLower().Contains(_ownerSearch.ToLower())
                        || c.Surname.ToLower().Contains(_ownerSearch.ToLower())
                        || c.Patronymic.ToLower().Contains(_ownerSearch.ToLower())
                    ).Take(maxResults)
                );
            }
        }

        /// <summary>
        /// Обновляет подсказки моделей двигателей
        /// </summary>
        private void UpdateEngineModelSuggestions()
        {
            var db = new Models.SASEntities();
            const int maxResults = 30;

            if (string.IsNullOrWhiteSpace(_engineModelSearch))
            {
                SuggestedEngineModels = new List<Models.EngineModel>(db.EngineModels.Take(maxResults));
            }
            else
            {
                SuggestedEngineModels = new List<Models.EngineModel>(
                    db.EngineModels.Where(em => em.Name.ToLower().Contains(_engineModelSearch.ToLower())).Take(maxResults)
                );
            }
        }

        private void CancelExecuted()
        {
            if (Popups.Confirm("отменить создание"))
            {
                Navigation.GoBack();
            }
        }

        private void SubmitExecuted()
        {
            // TODO: больше валидаций и проверок

            // 0. Проверки
            List<string> errors = new List<string>();

            bool vinIsCorrect = VINlib.VinInfo.CheckVIN(VIN);
            if (!vinIsCorrect)
            {
                errors.Add("Неверный VIN-номер");
            }

            if (errors.Count > 0)
            {
                Popups.ShowErrors(errors);
                return;
            }

            var db = new Models.SASEntities();

            // 1. Создать транспортное средство
            Models.Transport transport = new Models.Transport();
            transport.VIN = VIN;
            transport.TransportType = SelectedTransportType.ID;
            transport.Category = SelectedCategory.ID;
            transport.Model = SelectedModel.ID;
            transport.Color = SelectedColor.ID;
            transport.RelaseYear = int.Parse(ReleaseYear);
            transport.DriveType = SelectedDrive.ID;
            transport.MaxLoadKg = int.Parse(MaxLoad);
            transport.EngineNumber = EngineNumber;
            transport.EngineModel = SelectedEngineModel.ID;
            transport.WeightKg = int.Parse(Weight);
            transport.Comment = Comment;
            
            db.Transports.Add(transport);
            db.SaveChanges();

            // 2. Создать запись владельца
            Models.TransportOwnership ownership = new Models.TransportOwnership();
            ownership.Transport = transport.ID;
            ownership.Citizen = SelectedOwner.ID;
            ownership.CreatedAt = DateTime.Now;

            db.TransportOwnerships.Add(ownership);
            db.SaveChanges();
            
            Navigation.ToPortal();
        }
    }
}
