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?>? _attrs = null;
        private Dictionary<WineAttr, string>? _attrIds = null;
        private ObservableCollection<WineAttr>? _attrList = null;
        private bool _attrChanged = false;
        private bool _attrUpdate = false;

        private async Task WineAttributesInitEditing(AppDbContext ctx) {
            _attrList = new(await ctx.WineAttributes
                .OrderBy(a => a.Name)
                .ToListAsync());
            _attrs = _attrList.ToDictionary(a => a.AttrId, a => (string?)a.AttrId);
            _attrIds = _attrList.ToDictionary(a => a, a => a.AttrId);
            ControlUtils.RenewItemsSource(WineAttributeList, _attrList);
            WineAttributeList_SelectionChanged(null, null);
        }

        private async Task WineAttributesFinishEditing(AppDbContext ctx) {
            ControlUtils.RenewItemsSource(WineAttributeList, await ctx.WineAttributes
                .OrderBy(a => a.Name)
                .ToListAsync());
            _attrList = null;
            _attrs = null;
            _attrIds = null;
            _attrChanged = false;

            WineAttributeAddButton.IsEnabled = false;
            WineAttributeDeleteButton.IsEnabled = false;
        }

        private async Task WineAttributesSave(AppDbContext ctx) {
            if (!_attrChanged || _attrList == null || _attrs == null || _attrIds == null)
                return;

            foreach (var (attrid, _) in _attrs.Where(a => a.Value == null)) {
                ctx.Remove(ctx.WineAttributes.Find(attrid)!);
            }
            foreach (var (attr, old) in _attrIds) {
                attr.AttrId = old;
            }
            foreach (var (old, attrid) in _attrs.Where(a => a.Value != null)) {
                ctx.Update(ctx.WineAttributes.Find(old)!);
            }
            await ctx.SaveChangesAsync();

            foreach (var (old, attrid) in _attrs.Where(a => a.Value != null)) {
                await ctx.Database.ExecuteSqlAsync($"UPDATE wine_attribute SET attrid = {attrid} WHERE attrid = {old}");
                await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment_type SET vtrgid = (sortid || COALESCE(attrid, '') || COALESCE(disc, '')) WHERE attrid = {attrid}");
                await ctx.Database.ExecuteSqlRawAsync($"UPDATE payment_variant SET data = REPLACE(REPLACE(data, '/{old}\"', '/{attrid}\"'), '/{old}-', '/{attrid}-')");
            }
            await ctx.SaveChangesAsync();

            foreach (var attr in _attrList.Where(a => !_attrIds.ContainsKey(a))) {
                if (attr.AttrId == null) continue;
                ctx.Add(attr);
            }
            await ctx.SaveChangesAsync();
        }

        private void WineAttributeList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {
            UpdateButtons();
            _attrUpdate = true;
            if (WineAttributeList.SelectedItem is not WineAttr attr) {
                WineAttributeIdInput.Text = "";
                WineAttributeNameInput.Text = "";
                WineAttributeActiveInput.IsChecked = false;
                WineAttributeMaxKgPerHaInput.Text = "";
                WineAttributeStrictInput.IsChecked = false;
                WineAttributeFillLowerInput.SelectedItem = null;
            } else {
                WineAttributeIdInput.Text = attr.AttrId;
                WineAttributeNameInput.Text = attr.Name;
                WineAttributeActiveInput.IsChecked = attr.IsActive;
                WineAttributeMaxKgPerHaInput.Text = attr.MaxKgPerHa?.ToString() ?? "";
                WineAttributeStrictInput.IsChecked = attr.IsStrict;
                WineAttributeFillLowerInput.SelectedIndex = attr.FillLower;
            }
            _attrUpdate = false;
        }

        private void WineAttributeAddButton_Click(object sender, RoutedEventArgs evt) {
            if (_attrList == null) return;
            _attrChanged = true;
            var item = new WineAttr { AttrId = "", Name = "" };
            _attrList.Add(item);
            WineAttributeList.SelectedItem = item;
            UpdateButtons();
        }

        private void WineAttributeDeleteButton_Click(object sender, RoutedEventArgs evt) {
            if (_attrList == null || _attrs == null) return;
            _attrChanged = true;
            var idx = WineAttributeList.SelectedIndex;
            var item = _attrList[idx];
            _attrs[item.AttrId] = null;
            _attrList.RemoveAt(idx);
            WineAttributeList.SelectedIndex = idx < _attrList.Count ? idx : idx - 1;
            UpdateButtons();
        }

        private void WineAttribute_Changed(object? sender, RoutedEventArgs? evt) {
            if (_attrUpdate || (!IsEditing && !IsCreating) || WineAttributeList.SelectedItem is not WineAttr attr || _attrs == null || _attrIds == null) return;
            _attrChanged = _attrChanged ||
                WineAttributeIdInput.Text != attr.AttrId ||
                WineAttributeNameInput.Text != attr.Name ||
                WineAttributeActiveInput.IsChecked != attr.IsActive ||
                WineAttributeMaxKgPerHaInput.Text != attr.MaxKgPerHa?.ToString() ||
                WineAttributeStrictInput.IsChecked != attr.IsStrict ||
                WineAttributeFillLowerInput.SelectedIndex != attr.FillLower;

            var old = _attrIds.GetValueOrDefault(attr);
            var id = WineAttributeIdInput.Text;
            if (old != null) _attrs[old] = id;
            attr.AttrId = id;
            attr.Name = WineAttributeNameInput.Text ?? "";
            attr.IsActive = WineAttributeActiveInput.IsChecked ?? false;
            attr.MaxKgPerHa = WineAttributeMaxKgPerHaInput.Text.Length > 0 ? int.Parse(WineAttributeMaxKgPerHaInput.Text) : null;
            attr.IsStrict = WineAttributeStrictInput.IsChecked ?? false;
            attr.FillLower = WineAttributeFillLowerInput.SelectedIndex;

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

        private void WineAttributeIdInput_TextChanged(object sender, TextChangedEventArgs evt) {
            UpperCaseInput_TextChanged(sender, evt);
            WineAttribute_Changed(sender, evt);
        }

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

        private void WineAttributeStrictInput_Changed(object sender, RoutedEventArgs evt) {
            WineAttributeFillLowerInput.Visibility = WineAttributeStrictInput.IsChecked == true ? Visibility.Visible : Visibility.Hidden;
            WineAttributeFillLowerLabel.Visibility = WineAttributeFillLowerInput.Visibility;
            WineAttribute_Changed(sender, evt);
        }
    }
}
