using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.Metrics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using WGneu.Models;


namespace WGneu.Windows
{
    public partial class MemberListWindow : Window
    {
        private bool isEditing = false;
        private bool isCreating = false;
        private List<string> textFilter = new();
        private static RoutedCommand controlF = new RoutedCommand();
        private readonly WgContext context = new();

        public MemberListWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            RefreshMemberList();
            BranchInput.ItemsSource = context.Branches.OrderBy(b => b.Name).ToList();
            DefaultKgInput.ItemsSource = context.WbKgs.Select(k => k.Kg).OrderBy(k => k.Name).ToList();
            controlF.InputGestures.Add(new KeyGesture(Key.F, ModifierKeys.Control));
            CommandBindings.Add(new CommandBinding(controlF, FocusSearchInput));
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            context.Dispose();
            base.OnClosing(e);
        }

        private int CountMatchesInMember(Member m)
        {
            if (textFilter.Count == 0) return 0;
            string[] check = new string[] { m.MgNr.ToString(), m.FamilyName.ToLower(), m.GivenName.ToLower(), m.DefaultKg.Name.ToLower() };
            int i = 0;
            foreach (string c in check)
            {
                if (textFilter.Any(f => c == f))
                    i += 10;
                else if (textFilter.Any(f => c.Contains(f)))
                    i += 1;
            }
            return i;
        }

        private void RefreshMemberList()
        {
            context.Members.Load();
            List<Member> members = context.Members.OrderBy(m => m.FamilyName + " " + m.GivenName).ToList();

            if (textFilter.Count > 0)
            {
                members = members
                    .ToDictionary(m => m, m => CountMatchesInMember(m))
                    .OrderByDescending(a => a.Value)
                    .Where(a => a.Value > 0)
                    .Select(a => a.Key)
                    .ToList();
            }
            MemberList.ItemsSource = members;
            if (members.Count == 1)
                MemberList.SelectedIndex = 0;

            RefreshInputs();
        }

        private void RefreshInputs()
        {
            Member m = (Member)MemberList.SelectedItem;
            if (m != null)
            {
                EditMemberButton.IsEnabled = true;
                DeleteMemberButton.IsEnabled = true;
                FillInputs(m);
            }
            else
            {
                EditMemberButton.IsEnabled = false;
                DeleteMemberButton.IsEnabled = false;
                ClearInputs();
            }
        }

        private void InitInputs()
        {
            ClearInputs();
            MgNrInput.Text = NextMgNr().ToString();
        }

        private void MemberList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            RefreshInputs();
        }

        private void PlzInput_TextChanged(object sender, RoutedEventArgs e)
        {
            if (PlzInput.Text.Length == 4 && PlzInput.Text.All(char.IsDigit))
            {
                int plz = int.Parse(PlzInput.Text);
                var o = context.Postleitzahlen.Where(p => p.Plz == plz).ToHashSet();
                OrtInput.ItemsSource = o;
                OrtInput.SelectedItem = null;
            }
        }

        private void NewMemberButton_Click(object sender, RoutedEventArgs e)
        {
            isCreating = true;
            MemberList.IsEnabled = false;
            InitInputs();
            HideNewEditDeleteButtons();
            ShowSaveResetCancelButtons();
            UnlockInputs();
        }

        private void EditMemberButton_Click(object sender, RoutedEventArgs e)
        {
            if (MemberList.SelectedItem == null)
                return;

            isEditing = true;
            MemberList.IsEnabled = false;

            HideNewEditDeleteButtons();
            ShowSaveResetCancelButtons();
            UnlockInputs();
        }

        private void DeleteMemberButton_Click(object sender, RoutedEventArgs e)
        {
            Member m = (Member)MemberList.SelectedItem;
            if (m == null) return;

            var r = MessageBox.Show(
                $"Soll das Mitglied \"{m.FamilyName} {m.GivenName}\" (MgNr. {m.MgNr}) wirklich unwiderruflich gelöscht werden?",
                "Mitglied löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
            if (r == MessageBoxResult.Yes)
            {
                context.Remove(m);
                context.SaveChanges();
                RefreshMemberList();
            }
        }

        private void SaveButton_Click(object sender, RoutedEventArgs e)
        {
            // TODO only allow to click button, if values were checked

            Member? m = null;
            if (isEditing)
                m = (Member)MemberList.SelectedItem;
            else if (isCreating)
                m = new();

            int newMgNr = int.Parse(MgNrInput.Text);
            m.GivenName = GivenNameInput.Text;
            m.FamilyName = FamilyNameInput.Text;
            m.ZwstId = ((Branch)BranchInput.SelectedItem).ZwstId;
            m.CountryCode = "AT";
            m.PostalDestId = ((AT_Plz)OrtInput.SelectedItem).Id;
            m.PostalDest = context.PostalDestinations.Find(m.CountryCode, m.PostalDestId);
            m.Address = AddressInput.Text;
            m.DefaultKgNr = ((AT_Kg)DefaultKgInput.SelectedItem).KgNr;

            try
            {
                if (isEditing)
                    context.Update(m);
                else if (isCreating)
                    context.Add(m);
                context.SaveChanges();

                if (newMgNr != m.MgNr)
                    context.Database.ExecuteSql($"UPDATE member SET mgnr = {newMgNr} WHERE mgnr = {m.MgNr}");
            }
            catch (Exception exc)
            {
                MessageBox.Show(
                    "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message.ToString(),
                    "Mitglied aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
            }

            isEditing = false;
            isCreating = false;
            MemberList.IsEnabled = true;
            HideSaveResetCancelButtons();
            ShowNewEditDeleteButtons();
            LockInputs();
            RefreshMemberList();
        }

        private void ResetButton_Click(object sender, RoutedEventArgs e)
        {
            if (isEditing)
                RefreshInputs();
            else if (isCreating)
                InitInputs();
        }

        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            isEditing = false;
            isCreating = false;
            MemberList.IsEnabled = true;
            HideSaveResetCancelButtons();
            ShowNewEditDeleteButtons();
            RefreshInputs();
            LockInputs();
        }

        private void SearchInput_TextChanged(object sender, RoutedEventArgs e)
        {
            // TODO implement STRG+F
            textFilter = SearchInput.Text.ToLower().Split(" ").ToList().FindAll(s => s != "");
            RefreshMemberList();
        }

        private void FocusSearchInput(object sender, RoutedEventArgs e)
        {
            if (!isEditing && !isCreating)
            {
                SearchInput.Focus();
                SearchInput.SelectAll();
            }
        }

        private int NextMgNr()
        {
            int c = context.Members.Select(m => m.MgNr).Min();
            context.Members.OrderBy(m => m.MgNr).Select(m => m.MgNr).ToList().ForEach(a => { if (a <= c + 100) c = a; });
            return c + 1;
        }

        private void ShowSaveResetCancelButtons()
        {
            SaveButton.IsEnabled = true;
            ResetButton.IsEnabled = false;
            CancelButton.IsEnabled = true;
            SaveButton.Visibility = Visibility.Visible;
            ResetButton.Visibility = Visibility.Visible;
            CancelButton.Visibility = Visibility.Visible;
        }

        private void HideSaveResetCancelButtons()
        {
            SaveButton.IsEnabled = false;
            ResetButton.IsEnabled = false;
            CancelButton.IsEnabled = false;
            SaveButton.Visibility = Visibility.Hidden;
            ResetButton.Visibility = Visibility.Hidden;
            CancelButton.Visibility = Visibility.Hidden;
        }

        private void ShowNewEditDeleteButtons()
        {
            NewMemberButton.IsEnabled = true;
            EditMemberButton.IsEnabled = MemberList.SelectedItem != null;
            DeleteMemberButton.IsEnabled = MemberList.SelectedItem != null;
            NewMemberButton.Visibility = Visibility.Visible;
            EditMemberButton.Visibility = Visibility.Visible;
            DeleteMemberButton.Visibility = Visibility.Visible;
        }

        private void HideNewEditDeleteButtons()
        {
            NewMemberButton.IsEnabled = false;
            EditMemberButton.IsEnabled = false;
            DeleteMemberButton.IsEnabled = false;
            NewMemberButton.Visibility = Visibility.Hidden;
            EditMemberButton.Visibility = Visibility.Hidden;
            DeleteMemberButton.Visibility = Visibility.Hidden;
        }

        private void LockInputs()
        {
            MgNrInput.IsReadOnly = true;
            GivenNameInput.IsReadOnly = true;
            FamilyNameInput.IsReadOnly = true;
            AddressInput.IsReadOnly = true;
            PlzInput.IsReadOnly = true;
            OrtInput.IsEnabled = false;
            BranchInput.IsEnabled = false;
            DefaultKgInput.IsEnabled = false;
        }

        private void UnlockInputs()
        {
            MgNrInput.IsReadOnly = false;
            GivenNameInput.IsReadOnly = false;
            FamilyNameInput.IsReadOnly = false;
            AddressInput.IsReadOnly = false;
            PlzInput.IsReadOnly = false;
            OrtInput.IsEnabled = true;
            BranchInput.IsEnabled = true;
            DefaultKgInput.IsEnabled = true;
        }

        private void FillInputs(Member m)
        {
            MgNrInput.Text = m.MgNr.ToString();
            GivenNameInput.Text = m.GivenName;
            FamilyNameInput.Text = m.FamilyName;
            BranchInput.SelectedItem = m.Branch;
            DefaultKgInput.SelectedItem = m.DefaultKg;
            AddressInput.Text = m.Address;

            AT_Plz? p = m.PostalDest.Plz(context);
            if (p != null)
            {
                PlzInput.Text = p.Plz.ToString();
                OrtInput.ItemsSource = p.Orte(context);
                OrtInput.SelectedItem = p;
            }
            else
            {
                OrtInput.ItemsSource = null;
                OrtInput.SelectedItem = null;
            }
        }

        private void ClearInputs()
        {
            MgNrInput.Text = "";
            GivenNameInput.Text = "";
            FamilyNameInput.Text = "";
            BranchInput.SelectedItem = null;
            PlzInput.Text = "";
            OrtInput.SelectedItem = null;
            AddressInput.Text = "";
            DefaultKgInput.SelectedItem = null;
        }
    }
}