using Elwig.Helpers;
using Elwig.Models.Entities;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows;

namespace Elwig.Windows {
    public partial class BaseDataWindow {

        private Dictionary<string, string?>? _acts = null;
        private Dictionary<AreaComType, string>? _actIds = null;
        private ObservableCollection<AreaComType>? _actList = null;
        private bool _actChanged = false;
        private bool _actUpdate = false;

        private async Task AreaCommitmentTypesInitEditing(AppDbContext ctx) {
            _actList = new(await ctx.AreaCommitmentTypes
                .OrderBy(v => v.VtrgId)
                .Include(t => t.WineVar)
                .Include(t => t.WineAttr)
                .ToListAsync());
            _acts = _actList.ToDictionary(v => v.VtrgId, v => (string?)v.VtrgId);
            _actIds = _actList.ToDictionary(v => v, v => v.VtrgId);
            ControlUtils.RenewItemsSource(AreaCommitmentTypeList, _actList);
            AreaCommitmentTypeList_SelectionChanged(null, null);
        }

        private async Task AreaCommitmentTypesFinishEditing(AppDbContext ctx) {
            ControlUtils.RenewItemsSource(AreaCommitmentTypeList, await ctx.AreaCommitmentTypes
                .OrderBy(v => v.VtrgId)
                .Include(t => t.WineVar)
                .Include(t => t.WineAttr)
                .ToListAsync());
            _actList = null;
            _acts = null;
            _actIds = null;
            _actChanged = false;

            AreaCommitmentTypeAddButton.IsEnabled = false;
            AreaCommitmentTypeDeleteButton.IsEnabled = false;
        }

        private async Task AreaCommitmentTypesSave(AppDbContext ctx) {
            if (!_actChanged || _actList == null || _acts == null || _actIds == null)
                return;

            foreach (var (vtrgid, _) in _acts.Where(a => a.Value == null)) {
                ctx.Remove(ctx.AreaCommitmentTypes.Find(vtrgid)!);
            }
            foreach (var (attr, old) in _actIds) {
                attr.VtrgId = old;
            }
            foreach (var (old, vtrgid) in _acts.Where(a => a.Value != null)) {
                ctx.Update(ctx.AreaCommitmentTypes.Find(old)!);
            }
            await ctx.SaveChangesAsync();

            foreach (var (old, vtrgid) in _acts.Where(a => a.Value != null)) {
                await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment_type SET vtrgid = {vtrgid} WHERE vtrgid = {old}");
            }
            await ctx.SaveChangesAsync();

            foreach (var type in _actList.Where(a => !_actIds.ContainsKey(a))) {
                if (type.VtrgId == null) continue;
                ctx.Add(type);
            }
            await ctx.SaveChangesAsync();
        }

        private void AreaCommitmentTypeList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {
            UpdateButtons();
            _actUpdate = true;
            if (AreaCommitmentTypeList.SelectedItem is AreaComType type) {
                AreaCommitmentTypeIdInput.Text = $"{type.SortId}{type.AttrId}";
                ControlUtils.SelectItemWithPk(AreaCommitmentTypeWineVariantInput, type.SortId);
                ControlUtils.SelectItemWithPk(AreaCommitmentTypeWineAttributeInput, type.AttrId);
                AreaCommitmentTypeMinKgPerHaInput.Text = $"{type.MinKgPerHa}";
                AreaCommitmentTypePenaltyPerKgInput.Text = $"{type.PenaltyPerKg}";
                AreaCommitmentTypePenaltyInput.Text = $"{type.PenaltyAmount}";
                AreaCommitmentTypePenaltyNoneInput.Text = $"{type.PenaltyNone}";
            } else {
                AreaCommitmentTypeIdInput.Text = "";
                AreaCommitmentTypeWineVariantInput.SelectedItem = null;
                AreaCommitmentTypeWineAttributeInput.SelectedItem = null;
                AreaCommitmentTypeMinKgPerHaInput.Text = "";
                AreaCommitmentTypePenaltyPerKgInput.Text = "";
                AreaCommitmentTypePenaltyInput.Text = "";
                AreaCommitmentTypePenaltyNoneInput.Text = "";
            }
            _actUpdate = false;
        }

        private void AreaCommitmentTypeAddButton_Click(object sender, RoutedEventArgs evt) {
            if (_actList == null) return;
            _actChanged = true;
            var item = new AreaComType { VtrgId = "", SortId = "" };
            _actList.Add(item);
            AreaCommitmentTypeList.SelectedItem = item;
            UpdateButtons();
        }

        private void AreaCommitmentTypeDeleteButton_Click(object sender, RoutedEventArgs evt) {
            if (_actList == null || _acts == null) return;
            _actChanged = true;
            var idx = AreaCommitmentTypeList.SelectedIndex;
            var item = _actList[idx];
            _acts[item.VtrgId] = null;
            _actList.RemoveAt(idx);
            AreaCommitmentTypeList.SelectedIndex = idx < _actList.Count ? idx : idx - 1;
            UpdateButtons();
        }

        private void AreaCommitmentType_Changed(object? sender, RoutedEventArgs? evt) {
            if (_actUpdate || (!IsEditing && !IsCreating) || AreaCommitmentTypeList.SelectedItem is not AreaComType attr || _acts == null || _actIds == null) return;
            _actChanged = true;

            var v = AreaCommitmentTypeWineVariantInput.SelectedItem as WineVar;
            var a = AreaCommitmentTypeWineAttributeInput.SelectedItem as WineAttr;
            AreaCommitmentTypeIdInput.Text = $"{v?.SortId}{a?.AttrId}";

            var old = _actIds.GetValueOrDefault(attr);
            var id = AreaCommitmentTypeIdInput.Text;
            if (old != null) _acts[old] = id;
            attr.VtrgId = id;
            attr.SortId = v?.SortId;
            attr.AttrId = a?.AttrId;
            attr.MinKgPerHa = AreaCommitmentTypeMinKgPerHaInput.Text.Length > 0 ? int.Parse(AreaCommitmentTypeMinKgPerHaInput.Text) : null;
            attr.PenaltyPerKg = AreaCommitmentTypePenaltyPerKgInput.Text.Length > 0 ? decimal.Parse(AreaCommitmentTypePenaltyPerKgInput.Text) : null;
            attr.PenaltyAmount = AreaCommitmentTypePenaltyInput.Text.Length > 0 ? decimal.Parse(AreaCommitmentTypePenaltyInput.Text) : null;
            attr.PenaltyNone = AreaCommitmentTypePenaltyNoneInput.Text.Length > 0 ? decimal.Parse(AreaCommitmentTypePenaltyNoneInput.Text) : null;

            CollectionViewSource.GetDefaultView(_actList).Refresh();
            UpdateButtons();
        }

        private void AreaCommitmentTypeIdInput_TextChanged(object sender, TextChangedEventArgs evt) {
            UpperCaseInput_TextChanged(sender, evt);
            AreaCommitmentType_Changed(sender, evt);
        }

        private void AreaCommitmentTypeMinKgPerHa_TextChanged(object sender, TextChangedEventArgs evt) {
            InputTextChanged((TextBox)sender, Validator.CheckInteger((TextBox)sender, false, 5));
            AreaCommitmentType_Changed(sender, evt);
        }

        private void AreaCommitmentTypePenaltyPerKgInput_TextChanged(object sender, TextChangedEventArgs evt) {
            if (SeasonList.SelectedItem is not Season s) return;
            InputTextChanged((TextBox)sender, Validator.CheckDecimal((TextBox)sender, false, 2, s.Precision));
            AreaCommitmentType_Changed(sender, evt);
        }

        private void AreaCommitmentTypePenaltyInput_TextChanged(object sender, TextChangedEventArgs evt) {
            InputTextChanged((TextBox)sender, Validator.CheckDecimal((TextBox)sender, false, 4, 2));
            AreaCommitmentType_Changed(sender, evt);
        }
    }
}