using BodyshopPartner.Models;
using BodyshopPartner.Utils.Growls;
using GraphQL.Client;
using GraphQL;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Firebase.Auth;
using ToastNotifications.Messages;
using Microsoft.Win32;

namespace BodyshopPartner.ViewModels
{
    public partial class MainViewModel : BaseViewModel
    {
        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();


        /* * */

        public MainViewModel()
        {
            logger.Trace("Main VM constructed.");

            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += bw_InitVm;
            bw.WorkerReportsProgress = true;
            bw.ProgressChanged += Bw_ProgressChanged;
            bw.RunWorkerCompleted += Bw_RunWorkerCompleted;
            bw.RunWorkerAsync();

            Growler = new GrowlNotification(this);
            Utils.JobProcessingQueue.SetGrowler(Growler);
            Utils.QuickBooksInterop.SetGrowler(Growler);
        }

        private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            ((BackgroundWorker)sender).Dispose();
            Progress = 0;
        }

        private void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            Progress = e.ProgressPercentage;

            logger.Trace("Starting monitors if able to.");
            if (StartFolderMonitorsCommand.CanExecute(null))
                StartFolderMonitorsCommand.Execute(null);
            MonitoringPaths.CollectionChanged += MonitoringPathsChanged;
        }

        private void bw_InitVm(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker _callingThread = sender as BackgroundWorker;
            _callingThread.ReportProgress(1);

            //Restore list of paths, convert to monitor object.
            List<string> listOfPaths = Properties.Settings.Default.MonitoringPaths;
            if (listOfPaths == null) listOfPaths = new List<string>();
            foreach (var p in listOfPaths)
            {
                MonitoringPaths.Add(new Models.Monitor() { FilePath = p });
            }

            _callingThread.ReportProgress(30);

            _updateCheckTimer.Elapsed += _updateTimer_Elapsed;
            _updateCheckTimer.AutoReset = true;
            _updateCheckTimer.Start();

            _callingThread.ReportProgress(50);
            //Cannot use await.
            LoadBodyshopData().Wait(); ;

            _callingThread.ReportProgress(80);
            logger.Debug("VM Init Complete");
            Task.Run(() => Utils.HTTPServer.InitHttpServer(AddHttpStatus));
            Task.Run(() => updateCheck());
            _callingThread.ReportProgress(100);
        }


        private async Task updateCheck()
        {
            logger.Debug("Checking if updates are available.");
            UpdateAvailable = await Utils.UpdateHandler.AreUpdatesAvailable();
            if (UpdateAvailable)
            {
                string msg = "An update to ImEX Online Partner is Available";
                Utils.Notifications.notifier.ShowInformation(msg);
            }
        }

        private async Task InstallUpdates()
        {
            logger.Debug("Updates are available! Installing.");
            await Utils.UpdateHandler.ApplyUpdates(UpdateProgress, UpdateProgress);
        }

        private async void _updateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            await updateCheck();
        }

        private void MonitoringPathsChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            IndeterminateLoading = true;
            StopAllFolderMonitors();
            StartAllFolderMonitors();
            IndeterminateLoading = false;
        }

        public void AddFolderMonitoringPath()
        {
            var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
            if (dialog.ShowDialog().GetValueOrDefault())
            {
                logger.Debug("Adding folder {0} to monitoring paths.", dialog.SelectedPath);
                MonitoringPaths.Add(new Models.Monitor() { FilePath = dialog.SelectedPath });
                Properties.Settings.Default.MonitoringPaths = MonitoringPaths.Select(x => x.FilePath).ToList();
                Properties.Settings.Default.Save();
            }
        }

        public void RemoveFolderMonitoringPath(Monitor m)
        {
            logger.Debug("Removing folder {0} to monitoring paths.", m.FilePath);
            m.StopMonitor();
            MonitoringPaths.Remove(m);
            Properties.Settings.Default.MonitoringPaths = MonitoringPaths.Select(x => x.FilePath).ToList();
            Properties.Settings.Default.Save();
        }

        public void StartAllFolderMonitors()
        {
            IndeterminateLoading = true;
            if (MonitoringPaths.Count > 0)
                foreach (var m in MonitoringPaths)
                {
                    m.StopMonitor();
                }

            foreach (var p in MonitoringPaths)
            {
                p.StartMonitor();
            }
            IndeterminateLoading = false;
        }

        public void BrowseForQbFolder()
        {

            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Multiselect = false;
            openFileDialog.Filter = "QuickBooks files (*.qbw)|*.qbw|All files (*.*)|*.*";
            openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            if (openFileDialog.ShowDialog() == true)
            {

                Properties.Settings.Default.QuickBooksFilePath = openFileDialog.FileName;
                Properties.Settings.Default.Save();
            }


        }
        public void StopAllFolderMonitors()
        {
            IndeterminateLoading = true;
            if (MonitoringPaths.Count > 0)
                foreach (var m in MonitoringPaths)
                {
                    m.StopMonitor();
                }
            IndeterminateLoading = false;
        }

        public async Task LoadBodyshopData()
        {
            var r = new GraphQLRequest
            {
                Query = @"query QUERY_BODYSHOPS {
                                                  bodyshops {
                                                    shopname
                                                    id
                                                    region_config
                                                    associations {
                                                      id
                                                      active
                                                    }
                                                  }
                                                }"
            };

            var Data = await Utils.GraphQL.ExecuteQuery(r);
            if (Data != null)
            {
                ShopData = Data.bodyshops.ToObject<ObservableCollection<Bodyshop>>();
            }
            string SettingsSelectedShopUuid = Properties.Settings.Default.LastSelectedShop;
            if (string.IsNullOrEmpty(SettingsSelectedShopUuid))
            {
                ActiveShop = ShopData[0] ?? null;
                Properties.Settings.Default.LastSelectedShop = ShopData[0]?.Id ?? null;
                Properties.Settings.Default.Save();
            }
            else
            {
                ActiveShop = ShopData.Where(_ => _.Id == SettingsSelectedShopUuid).FirstOrDefault();
            }
        }

        public async Task SetActiveBodyshop()
        {
            IndeterminateLoading = true;
            foreach (var s in ShopData)
            {
                if (s.Id == ActiveShop?.Id) s.AssociationActive = true;
                else s.AssociationActive = false;
                var r = new GraphQLRequest
                {
                    Query = @"
                        mutation UPDATE_ASSOCIATION($assocId: uuid, $assocActive: Boolean) {
                            update_associations(where: {id: {_eq: $assocId}}, _set: {active: $assocActive}) {
                                returning {
                                    id
                                    active
                                }
                            }
                        }
            ",
                    Variables = new
                    {
                        assocId = s.AssociationId,
                        assocActive = s.AssociationActive
                    }
                };
                await Utils.GraphQL.ExecuteQuery(r);
            }
            Properties.Settings.Default.LastSelectedShop = ActiveShop?.Id;
            Properties.Settings.Default.Save();
            Utils.AppMetaData.ActiveShopId = ActiveShop?.Id;
            Utils.AppMetaData.ShopRegion = ActiveShop?.RegionConfig;
            IndeterminateLoading = false;
        }

        public void AddHttpStatus(string s)
        {
            string newLine = $"\n{DateTime.Now.ToString("MM/dd/yy hh:mm:ss tt")}: {s}";
            HttpServerLog += newLine;
            logger.Trace(newLine);
        }

        private FirebaseAuthLink al = BodyshopPartner.Utils.Auth.authlink;
        public async Task TestGql()
        {

            Utils.SquirrelAwareHelper.AddHttpExcetion();

        }
    }
}
