using System.IO;
using System.Windows;
using System.Windows.Controls;
using FastReport;
using FastReport.Export;
using FastReport.Export.BIFF8;
using FastReport.Export.Html;
using FastReport.Export.Image;
using FastReport.Export.Pdf;
using FastReport.Export.RichText;
using FastReport.Export.Text;
using InABox.Clients;
using InABox.Core;
using InABox.WPF;
using Button = System.Windows.Controls.Button;
using Image = System.Windows.Controls.Image;
using SaveFileDialog = Microsoft.Win32.SaveFileDialog;
using System;
using InABox.Wpf;
using TextBox = System.Windows.Controls.TextBox;
using InABox.Core.Reports;
using ICSharpCode.AvalonEdit.Highlighting;
using System.Drawing;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Threading;
using FastReport.Design;
using Syncfusion.Windows.Controls.RichTextBoxAdv;

namespace InABox.Wpf.Reports
{
    /// <summary>
    ///     Interaction logic for PreviewWindow.xaml
    /// </summary>
    public partial class PreviewWindow : ThemableWindow
    {
        private Report _report;
        private readonly ReportTemplate _template;
        private readonly DataModel _model;
        private bool modelIsPopulated;

        public Action<ReportTemplate>? SaveTemplate { get; set; } = null;

        public PreviewWindow(ReportTemplate template, DataModel model)
        {
            InitializeComponent();

            _template = template;
            _model = model;
            modelIsPopulated = false;

            PrintButton.Content = ImageUtils.CreatePreviewWindowButtonContent("Print",Wpf.Resources.print);
            SavePDFButton.Content = ImageUtils.CreatePreviewWindowButtonContent("Save PDF", Wpf.Resources.save);
            SaveRTFButton.Content = ImageUtils.CreatePreviewWindowButtonContent("Save RTF", Wpf.Resources.save);
            SaveExcelButton.Content = ImageUtils.CreatePreviewWindowButtonContent("Save Excel", Wpf.Resources.save);

            foreach (var def in ReportUtils.ExportDefinitions)
            {
                var button = new Button();
                if (def.Control != null)
                    button.Content = def.Control;
                else
                    button.Content = GetImage(def.Image);

                button.VerticalAlignment = VerticalAlignment.Top;
                button.Click += (o, e) =>
                {
                    var data = ExportReport(def.Type);
                    def.Action.Invoke(model, data);
                };
                Toolbar.Items.Insert(Toolbar.Items.IndexOf(ExportSeparator), button);
            }

            //EmailButton.Content = GetImage(Wpf.Resources.email);
            FirstButton.Content = ImageUtils.CreatePreviewWindowButtonContent("First",Wpf.Resources.first);
            BackButton.Content = ImageUtils.CreatePreviewWindowButtonContent("Back",Wpf.Resources.back);
            NextButton.Content = ImageUtils.CreatePreviewWindowButtonContent("Next",Wpf.Resources.next);
            LastButton.Content = ImageUtils.CreatePreviewWindowButtonContent("Last",Wpf.Resources.last);
            ZoomInButton.Content = ImageUtils.CreatePreviewWindowButtonContent("Zoom In",Wpf.Resources.zoomin);
            ZoomOutButton.Content = ImageUtils.CreatePreviewWindowButtonContent("Zoom Out",Wpf.Resources.zoomout);
            DesignButton.Content = ImageUtils.CreatePreviewWindowButtonContent("Design",Wpf.Resources.pencil);

            Loaded += PreviewWindow_Loaded;

            Editor.TextChanged += Editor_TextChanged;
            Designer.InnerDesigner.cmdSave.CustomAction += (sender, args) => SaveReport();
            Designer.InnerDesigner.cmdSaveAs.CustomAction += (sender, args) => SaveReportAs();
            Designer.InnerDesigner.cmdPreview.CustomAction += (sender, args) => ShowPreview();
            Designer.InnerDesigner.AskSave = false;


        }

        private void SaveReportAs()
        {
            var dialog = new SaveFileDialog();
            dialog.Filter = "Report files (*.frx)|*.frx";
            dialog.FileName = _template.Name + ".frx";
            if (dialog.ShowDialog() == true)
                Designer.Report.Save(dialog.FileName);
        }

        // private void CustomSaveReport(object sender, OpenSaveReportEventArgs e)
        // {
        //     SaveReport();
        // }
        //
        // private void CustomSaveReportAs(object sender, OpenSaveDialogEventArgs e)
        // {
        //     var dialog = new SaveFileDialog();
        //     dialog.Filter = "Report files (*.frx)|*.frx";
        //     dialog.FileName = _template.Name + ".frx";
        //     if (dialog.ShowDialog() == true)
        //         Designer.Report.Save(dialog.FileName);
        // }
        //
        // private void CustomPreviewReport(object? sender, EventArgs e)
        // {
        //     ShowPreview();
        // }
        
        private void Editor_TextChanged(object? sender, EventArgs e)
        {
        }

        public bool IsPreview { get; set; } = true;
        public bool ShouldPopulate { get; set; } = true;

        public Report Report
        {
            get => _report;
            set
            {
                _report = value;
                Designer.Report = value;
                Refresh();
            }
        }

        public bool AllowDesign
        {
            get => DesignButton.Visibility == Visibility.Visible;
            set => DesignButton.Visibility = value ? Visibility.Visible : Visibility.Collapsed;
        }

        private Image GetImage(Bitmap bitmap)
        {
            return new Image
            {
                Source = bitmap.AsBitmapImage(),
                Height = 32.0F,
                Width = 32.0F,
                Margin = new Thickness(10)
            };
        }

        private void DisplayLoading()
        {
            PreviewGrid.RowDefinitions[1].Height = new GridLength(0);
            PreviewGrid.RowDefinitions[2].Height = new GridLength(1, GridUnitType.Star);
            DesignButton.IsEnabled = false;
        }
        private void CloseLoading()
        {
            PreviewGrid.RowDefinitions[1].Height = new GridLength(1, GridUnitType.Star);
            PreviewGrid.RowDefinitions[2].Height = new GridLength(0);
            DesignButton.IsEnabled = true;
        }

        private void SetupReport(Action action)
        {
            DisplayLoading();
            Task.Run(() =>
            {
                try
                {
                    _report ??= ReportUtils.SetupReport(_template, _model, ShouldPopulate && !modelIsPopulated);
                    return null;
                }
                catch (Exception e)
                {
                    Logger.Send(LogType.Error,"",$"SetupReport() returned an error!\n{e.Message}\n{e.StackTrace}");
                    return e.Message;
                }
            }).ContinueWith((s) =>
            {
                try
                {
                    if (s.Result == null)
                    {
                        Dispatcher.BeginInvoke(() =>
                        {
                            try
                            {
                                Designer.Report ??= _report;
                                action();
                                CloseLoading();
                            }
                            catch (Exception e)
                            {
                                MessageWindow.ShowError("Some errors were found in this report.", e.Message, "Errors in report");
                                CloseLoading();
                                ShowDesigner();
                            }
   
                        });
                    }
                    else
                    {
                        Dispatcher.BeginInvoke(() =>ShowEditor(s.Result));
                    }
                }
                catch (Exception e)
                {
                    Logger.Send(LogType.Error,"",$"An Error occurred while loading the report window!\n{e.Message}\n{e.StackTrace}");
                    Dispatcher.BeginInvoke(() =>ShowEditor(e.Message));
                }
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }

        private void ShowPreview()
        {
            MainGrid.RowDefinitions[0].Height = new GridLength(1, GridUnitType.Star);
            MainGrid.RowDefinitions[1].Height = new GridLength(0);
            MainGrid.RowDefinitions[2].Height = new GridLength(0);

            Title = string.Format("Report Preview - {0}", _template.Name);

            SetupReport(() => Refresh());
        }

        private void ShowDesigner()
        {
            MainGrid.RowDefinitions[0].Height = new GridLength(0);
            MainGrid.RowDefinitions[1].Height = new GridLength(1, GridUnitType.Star);
            MainGrid.RowDefinitions[2].Height = new GridLength(0);

            SetupReport(() =>
            {
                Title = string.Format("Report Designer - {0}", Report.FileName);
                //Designer.InnerDesigner.RefreshLayout();
            });
        }

        private void ShowEditor(string err)
        {
            MainGrid.RowDefinitions[0].Height = new GridLength(0);
            MainGrid.RowDefinitions[1].Height = new GridLength(0);
            MainGrid.RowDefinitions[2].Height = new GridLength(1, GridUnitType.Star);

            Title = string.Format("Edit Report Template - {0}", _template.Name);

            Editor.Text = _report?.SaveToString() ?? (String.IsNullOrWhiteSpace(_template.RDL) ? "" : _template.RDL);
            Editor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("XML");

            System.Windows.MessageBox.Show("There was an error loading the report. The raw XML data has been loaded here.\n\nError Message:\n" + (err.Length < 200 ? err : string.Concat(err.AsSpan(0, 200), "...")));
        }

        private void PreviewWindow_Loaded(object sender, RoutedEventArgs e)
        {
            if (IsPreview)
            {
                ShowPreview();
            }
            else
            {
                ShowDesigner();
            }
        }

        private class Exporter
        {
            public Type Export { get; }

            public string FileExtension { get; }

            public string FileFilter { get; }

            public Exporter(Type export, string fileExtension, string fileFilter)
            {
                Export = export;
                FileExtension = fileExtension;
                FileFilter = fileFilter;
            }
        }

        private static readonly Dictionary<ReportExportType, Exporter> _exporters = new Dictionary<ReportExportType, Exporter>
        {
            { ReportExportType.PDF, new Exporter(typeof(PDFExport), ".pdf", "PDF Files (*.pdf)|*.pdf") },
            { ReportExportType.HTML, new Exporter(typeof(HTMLExport), ".html", "HTML Files (*.html)|*.html") },
            { ReportExportType.RTF, new Exporter(typeof(RTFExport), ".rtf", "RTF Files (*.rtf)|*.rtf") },
            { ReportExportType.Excel, new Exporter(typeof(Excel2003Document), ".xls", "Excel Files (*.xls)|*.xls") },
            { ReportExportType.Text, new Exporter(typeof(TextExport), ".txt", "Text Files (*.txt)|*.txt") },
            { ReportExportType.Image, new Exporter(typeof(ImageExport), ".jpg", "JPEG Files (*.jpg, *.jpeg)|*.jpg;*.jpeg") }
        };

        private byte[] ExportReport(ReportExportType type)
        {
            using var ms = new MemoryStream();
            _report.Export(Activator.CreateInstance(_exporters[type].Export) as ExportBase, ms);
            return ms.GetBuffer();
        }

        private void Refresh()
        {
            _report.WpfPreview = Preview;
            // var assyname = typeof(TheArtOfDev.HtmlRenderer.WPF.HtmlRender).Assembly.FullName.Split(',').First();
            // AppDomain.CurrentDomain.Load("HtmlRenderer.Ddll");
            // AppDomain.CurrentDomain.Load("HtmlRenderer.Wpf.dll");
            // _report.AddReferencedAssembly("HtmlRendere");
            _report.Prepare();
            _report.ShowPrepared();
            Preview.Zoom = 1.0F;
        }

        private void PrintButton_Click(object sender, RoutedEventArgs e)
        {
            Report.PrintPrepared();
        }

        private void SaveButton_Click(object sender, RoutedEventArgs e)
        {
            var exporter = _exporters[(ReportExportType)((Button)sender).Tag];
            var dlg = new SaveFileDialog();
            dlg.Filter = exporter.FileFilter;
            dlg.FileName = Path.ChangeExtension(Report.FileName, exporter.FileExtension);
            if (dlg.ShowDialog() == true)
                Report.Export(Activator.CreateInstance(exporter.Export) as ExportBase, dlg.FileName);
        }


        //private void EmailButton_Click(object sender, RoutedEventArgs e)
        //{
        //    String attachment = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.ChangeExtension(Report.FileName,".pdf"));
        //    using (new WaitCursor())
        //    {
        //        using (var filestream = System.IO.File.Open(attachment, System.IO.FileMode.Create))
        //        {
        //            _report.Export(new PDFExport(), filestream);
        //            filestream.Close();
        //        }
        //    }

        //    //Outlook.Application outlookApp = new Outlook.Application();
        //    //Outlook.MailItem mailItem = (Outlook.MailItem)outlookApp.CreateItem(Outlook.OlItemType.olMailItem);
        //    //mailItem.Subject = System.IO.Path.ChangeExtension(Report.FileName,"");
        //    //mailItem.To = "";
        //    //mailItem.HTMLBody = "";
        //    //mailItem.Attachments.Add(attachment, Outlook.OlAttachmentType.olByValue, Type.Missing, Type.Missing);
        //    //mailItem.Display(false);

        //}

        private void FirstButton_Click(object sender, RoutedEventArgs e)
        {
            Preview.First();
        }

        private void BackButton_Click(object sender, RoutedEventArgs e)
        {
            Preview.Prior();
        }

        private void NextButton_Click(object sender, RoutedEventArgs e)
        {
            Preview.Next();
        }

        private void LastButton_Click(object sender, RoutedEventArgs e)
        {
            Preview.Last();
        }

        private void ZoomInButton_Click(object sender, RoutedEventArgs e)
        {
            Preview.ZoomIn();
        }

        private void ZoomOutButton_Click(object sender, RoutedEventArgs e)
        {
            Preview.ZoomOut();
        }

        private void SaveReport()
        {
            _template.RDL = _report.SaveToString();
            DoSave(_template);
            Designer.Report = _report;
            Designer.InnerDesigner.Modified = false;
        }

        private void DesignButton_Click(object sender, RoutedEventArgs e)
        {
            ShowDesigner();
        }

        private void ToolBar_Loaded(object sender, RoutedEventArgs e)
        {
            var toolBar = sender as ToolBar;
            var overflowGrid = toolBar.Template.FindName("OverflowGrid", toolBar) as FrameworkElement;
            if (overflowGrid != null) overflowGrid.Visibility = Visibility.Collapsed;
            var mainPanelBorder = toolBar.Template.FindName("MainPanelBorder", toolBar) as FrameworkElement;
            if (mainPanelBorder != null) mainPanelBorder.Margin = new Thickness();

            var grid = toolBar.Template.FindName("Grid", toolBar) as FrameworkElement;
            if (grid != null) grid.Margin = new Thickness();
        }

        private void DoSave(ReportTemplate template)
        {
            if (SaveTemplate is null)
            {
                Progress.ShowModal("Saving", p =>
                {
                    new Client<ReportTemplate>().Save(template, "Updated by Designer");
                });
            }
            else
                SaveTemplate?.Invoke(template);
        }

        private void SaveEditorButton_Click(object sender, RoutedEventArgs e)
        {
            _template.RDL = Editor.Text;
            DoSave(_template);
            _report = null;
            ShowPreview();
        }

        private void PreviewWindow_OnClosing(object? sender, CancelEventArgs e)
        {
            if (Designer.InnerDesigner.Modified)
            {
                var result = MessageWindow.ShowYesNoCancel("There are unsaved changes in this report!\nDo you wish to save them now?","Save Changes");
                if (result == MessageWindowResult.Cancel)
                {
                    e.Cancel = true;
                    return;
                }
                if (result == MessageWindowResult.Yes)
                    SaveReport();
            }
        }
    }
}