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

namespace Elwig.Windows {
    public partial class BaseDataWindow {

        private Dictionary<string, string?>? _mods = null;
        private Dictionary<Modifier, string>? _modIds = null;
        private ObservableCollection<Modifier>? _modList = null;
        private bool _modChanged = false;
        private bool _modUpdate = false;

        private async Task ModifiersInitEditing(AppDbContext ctx) {
            SeasonList.IsEnabled = false;
            var year = (SeasonList.SelectedItem as Season)?.Year;
            _modList = new(await ctx.Modifiers
                .Where(m => m.Year == year)
                .OrderBy(m => m.Ordering)
                .ToListAsync());
            _mods = _modList.ToDictionary(m => m.ModId, m => (string?)m.ModId);
            _modIds = _modList.ToDictionary(m => m, m => m.ModId);
            ControlUtils.RenewItemsSource(SeasonModifierList, _modList);
            SeasonModifierList_SelectionChanged(null, null);
        }

        private async Task ModifiersFinishEditing(AppDbContext ctx) {
            var year = (SeasonList.SelectedItem as Season)?.Year;
            ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.Modifiers
                .Where(m => m.Year == year)
                .OrderBy(m => m.Ordering)
                .ToListAsync());
            _modList = null;
            _mods = null;
            _modIds = null;
            _modChanged = false;

            SeasonModifierUpButton.IsEnabled = false;
            SeasonModifierDownButton.IsEnabled = false;
            SeasonModifierAddButton.IsEnabled = false;
            SeasonModifierDeleteButton.IsEnabled = false;
            SeasonList.IsEnabled = true;
        }

        private async Task ModifiersSave(AppDbContext ctx) {
            if (!_modChanged || _modList == null || _mods == null || _modIds == null)
                return;

            int i = 0;
            foreach (var mod in _modList) mod.Ordering = ++i;

            var year = (SeasonList.SelectedItem as Season)?.Year;
            foreach (var (modid, _) in _mods.Where(m => m.Value == null)) {
                ctx.Remove(ctx.Modifiers.Find(year, modid)!);
            }
            foreach (var (mod, old) in _modIds) {
                mod.ModId = old;
            }
            foreach (var (old, modid) in _mods.Where(m => m.Value != null)) {
                ctx.Update(ctx.Modifiers.Find(year, old)!);
            }
            await ctx.SaveChangesAsync();

            foreach (var (old, modid) in _mods.Where(m => m.Value != null)) {
                await ctx.Database.ExecuteSqlAsync($"UPDATE modifier SET modid = {modid} WHERE (year, modid) = ({year}, {old})");
            }
            await ctx.SaveChangesAsync();

            foreach (var mod in _modList.Where(m => !_modIds.ContainsKey(m))) {
                if (mod.ModId == null) continue;
                await ctx.AddAsync(mod);
            }
            await ctx.SaveChangesAsync();
        }

        private void SeasonModifierUpButton_Click(object sender, RoutedEventArgs evt) {
            if (_modList == null) return;
            _modChanged = true;
            var idx = SeasonModifierList.SelectedIndex;
            var item = _modList[idx];
            _modList.RemoveAt(idx);
            idx--;
            _modList.Insert(idx, item);
            SeasonModifierList.SelectedIndex = idx;
            UpdateButtons();
        }

        private void SeasonModifierDownButton_Click(object sender, RoutedEventArgs evt) {
            if (_modList == null) return;
            _modChanged = true;
            var idx = SeasonModifierList.SelectedIndex;
            var item = _modList[idx];
            _modList.RemoveAt(idx);
            idx++;
            _modList.Insert(idx, item);
            SeasonModifierList.SelectedIndex = idx;
            UpdateButtons();
        }

        private void SeasonModifierAddButton_Click(object sender, RoutedEventArgs evt) {
            if (_modList == null || SeasonList.SelectedItem is not Season s) return;
            _modChanged = true;
            var idx = (SeasonModifierList.SelectedIndex != -1) ? SeasonModifierList.SelectedIndex + 1 : _modList.Count;
            var item = new Modifier { Year = s.Year, ModId = "", Name = "" };
            _modList.Insert(idx, item);
            SeasonModifierList.SelectedIndex = idx;
            UpdateButtons();
        }

        private void SeasonModifierDeleteButton_Click(object sender, RoutedEventArgs evt) {
            if (_modList == null || _mods == null) return;
            _modChanged = true;
            var idx = SeasonModifierList.SelectedIndex;
            var item = _modList[idx];
            _mods[item.ModId] = null;
            _modList.RemoveAt(idx);
            SeasonModifierList.SelectedIndex = idx < _modList.Count ? idx : idx - 1;
            UpdateButtons();
        }

        private void SeasonModifierList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {
            UpdateButtons();
            _modUpdate = true;
            if (SeasonModifierList.SelectedItem is not Modifier mod) {
                SeasonModifierIdInput.Text = "";
                SeasonModifierNameInput.Text = "";
                SeasonModifierRelInput.Text = "";
                SeasonModifierAbsInput.Text = "";
                SeasonModifierActiveInput.IsChecked = false;
                SeasonModifierRedactedInput.IsChecked = false;
            } else {
                SeasonModifierIdInput.Text = mod.ModId;
                SeasonModifierNameInput.Text = mod.Name;
                SeasonModifierRelInput.Text = (mod.Rel * 100)?.ToString() ?? "";
                SeasonModifierAbsInput.Text = mod.Abs?.ToString() ?? "";
                SeasonModifierActiveInput.IsChecked = mod.IsActive;
                SeasonModifierRedactedInput.IsChecked = mod.IsRedacted;
            }
            _modUpdate = false;
        }

        private void SeasonModifier_Changed(object? sender, RoutedEventArgs? evt) {
            if (_modUpdate || (!IsEditing && !IsCreating) || SeasonModifierList.SelectedItem is not Modifier mod || SeasonList.SelectedItem is not Season s || _mods == null || _modIds == null) return;
            _modChanged = true;

            var old = _modIds.GetValueOrDefault(mod);
            var id = SeasonModifierIdInput.Text ?? "";
            if (old != null) _mods[old] = id;
            mod.ModId = id;
            mod.Name = SeasonModifierNameInput.Text;
            mod.Rel = decimal.TryParse(SeasonModifierRelInput.Text, out var vRel) ? vRel / 100 : null;
            mod.AbsValue = decimal.TryParse(SeasonModifierAbsInput.Text, out var vAbs) ? Utils.DecToDb(vAbs, s.Precision) : null;
            mod.IsActive = SeasonModifierActiveInput.IsChecked ?? false;
            mod.IsRedacted = SeasonModifierRedactedInput.IsChecked ?? false;

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

        private void SeasonModifierIdInput_TextChanged(object sender, TextChangedEventArgs evt) {
            UpperCaseInput_TextChanged(sender, evt);
            SeasonModifier_Changed(sender, evt);
        }

        private void SeasonModifierRelInput_TextChanged(object sender, TextChangedEventArgs evt) {
            InputTextChanged((TextBox)sender, Validator.CheckDecimal((TextBox)sender, false, 3, 2, true));
            if (SeasonModifierRelInput.Text.Length > 0 && SeasonModifierAbsInput.Text.Length > 0)
                SeasonModifierAbsInput.Text = "";
            SeasonModifier_Changed(sender, evt);
        }

        private void SeasonModifierAbsInput_TextChanged(object sender, TextChangedEventArgs evt) {
            if (SeasonList.SelectedItem is not Season s) return;
            InputTextChanged((TextBox)sender, Validator.CheckDecimal((TextBox)sender, false, 2, s.Precision, true));
            if (SeasonModifierAbsInput.Text.Length > 0 && SeasonModifierRelInput.Text.Length > 0)
                SeasonModifierRelInput.Text = "";
            SeasonModifier_Changed(sender, evt);
        }
    }
}
