using System;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Ookii.Dialogs.Wpf;
using EDJournal;
using EliteBGS.BGS;
using EliteBGS.Util;
using EliteBGS.UI;
using EliteBGS.EDDB;

namespace EliteBGS {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window {
        private PlayerJournal journal = null;
        private Report report = new Report();
        private Config config = new Config();
        private API api = null;

        private PopulatedSystems systems_db = null;
        private Stations stations_db = null;

        public Config Config => config;

        public Report Report => report;

        public MainWindow() {
            InitializeComponent();

            try {
                config.LoadGlobal();
            } catch (Exception) {
                /* ignored */
            }

            report.OnLog += Report_OnLog;

            LogType.Items.Add(new NonaDiscordLog());
            LogType.Items.Add(new GenericDiscordLog());
            LogType.SelectedIndex = 0;

            api = new API(config.ConfigPath);
            journal = new PlayerJournal(config.Global.JournalLocation);

            // Set both to now
            startdate.SelectedDate = DateTime.Now;
            enddate.SelectedDate = DateTime.Now;
            journallocation.Text = Config.Global.JournalLocation;
            useeddb.IsChecked = Config.Global.UseEDDB;

            try {
                config.LoadObjectives(Report);
                RefreshObjectives();
            } catch (Exception e) {
                Log(e.Message);
            }

            api.SystemsAvailable += Api_SystemsAvailable;
            api.StationsAvailable += Api_StationsAvailable;

            try {
                api.CheckDatabases();
            } catch (Exception e) {
                Log(e.Message);
            }
        }

        private void Api_StationsAvailable() {
            try {
                stations_db = api.MakeStations();
            } catch (Exception e) {
                Log(e.Message);
            }
        }

        private void Api_SystemsAvailable() {
            try {
                systems_db = api.MakePopulatedSystems();
                system.Provider = new SystemSuggestionProvider(systems_db);
            } catch (Exception e) {
                Log(e.Message);
            }
        }

        private void Report_OnLog(string message) {
            StringBuilder builder = new StringBuilder();

            builder.Append(DateTime.Now.ToString());
            builder.Append(": ");
            builder.Append(message);
            builder.Append("\n");

            log.AppendText(builder.ToString());
        }

        private void Log(string message) {
            Report_OnLog(message);
        }

        private void RefreshObjectives() {
            entries.Items.Clear();

            if (report.Objectives == null) {
                return;
            }

            foreach (Objective obj in report.Objectives) {
                entries.Items.Add(obj);
                obj.IsExpanded = obj.ManuallyAdded;
                obj.IsEnabled = obj.ManuallyAdded;
            }
        }

        private void ParseJournal_Click(object sender, RoutedEventArgs e) {
            try {
                journal.Open(); // Load all files
                var start = startdate.SelectedDate ?? DateTime.Now;
                var end = startdate.SelectedDate ?? DateTime.Now;
                report.Scan(journal, start, end);
                RefreshObjectives();
            } catch (Exception exception) {
                Log("Something went terribly wrong while parsing the E:D player journal.");
                Log("Please send this to CMDR Hekateh:");
                Log(exception.ToString());
            }
        }

        private void AddObjective() {
            Objective objective = new Objective {
                System = system.Text,
                Faction = faction.Text,
                Station = station.Text,
                ManuallyAdded = true,
            };

            if (!objective.IsValid) {
                return;
            }

            if (report.AddObjective(objective)) {
                RefreshObjectives();
                config.SaveObjectives(Report);
            }
        }

        private void AddFilter_Click(object sender, RoutedEventArgs e) {
            AddObjective();
        }

        private void GenerateDiscord_Click(object sender, RoutedEventArgs e) {
            try {
                IDiscordLogGenerator discord = LogType.SelectedItem as IDiscordLogGenerator;
                string report = discord.GenerateDiscordLog(Report);

                DiscordLog.Text = report;
            } catch (Exception exception) {
                Log("Something went terribly wrong while generating the Discord log.");
                Log("Please send this to CMDR Hekateh:");
                Log(exception.ToString());
            }
        }

        private void RemoveCurrentObjective() {
            if (entries.SelectedItem == null) {
                return;
            }

            object obj = entries.SelectedItem;
            bool removed = false;

            if (obj.GetType() == typeof(Objective)) {
                removed = report.Objectives.Remove(obj as Objective);
            } else if (obj.GetType() == typeof(LogEntry) ||
                obj.GetType().IsSubclassOf(typeof(LogEntry))) {
                foreach (Objective parent in report.Objectives) {
                    if (parent.LogEntries.Remove(obj as LogEntry)) {
                        removed = true;
                    }
                }
            }

            if (removed) {
                RefreshObjectives();
                config.SaveObjectives(Report);
            }
        }

        private void entries_KeyUp(object sender, KeyEventArgs e) {
            if (e.Key == Key.Delete) {
                RemoveCurrentObjective();
            }
        }

        private void browsejournallocation_Click(object sender, RoutedEventArgs e) {
            var dialog = new VistaFolderBrowserDialog();

            if ((bool)!dialog.ShowDialog()) {
                return;
            }

            Config.Global.JournalLocation = dialog.SelectedPath;
            journallocation.Text = Config.Global.JournalLocation;
            journal = new PlayerJournal(config.Global.JournalLocation);
        }

        private void useeddb_Click(object sender, RoutedEventArgs e) {
            Config.Global.UseEDDB = (bool)useeddb.IsChecked;
        }

        private void Filter_KeyDown(object sender, KeyEventArgs e) {
            if (e.Key == Key.Enter) {
                AddObjective();
            }
        }

        private void station_GotFocus(object sender, RoutedEventArgs e) {
            try {
                if (stations_db == null || systems_db == null) {
                    return;
                }

                var sys = system.Text;
                if (sys == null || sys.Length <= 0) {
                    return;
                }

                int system_id = systems_db.ToId(sys);
                station.Provider = new StationSuggestionProvider(stations_db, system_id);
            } catch (Exception exc) {
                Log(exc.ToString());
            }
        }

        private void DownloadData_Click(object sender, RoutedEventArgs e) {
            if (!Config.Global.UseEDDB) {
                return;
            }

            ProgressDialog dialog = new ProgressDialog(api);
            dialog.StartDownload();
            dialog.ShowDialog();
        }

        private void AddCombatZone_Click(object sender, RoutedEventArgs e) {
            if (entries.SelectedItem == null) {
                return;
            }

            TreeViewItem item = entries.SelectedItem as TreeViewItem;
            var obj = item.Tag;

            if (obj.GetType() != typeof(Objective)) {
                return;
            }

            Objective objective = obj as Objective;

            CombatZoneDialog dialog = new CombatZoneDialog() { Owner = this };

            if (!(dialog.ShowDialog() ?? false)) {
                return;
            }

            CombatZone zone = new CombatZone();

            zone.ManuallyAdded = true;
            zone.Faction = objective.Faction;
            zone.System = objective.System;
            zone.Station = objective.Station;

            zone.Grade = dialog.Grade;
            zone.Type = dialog.Type;
            zone.Amount = dialog.Amount;

            objective.LogEntries.Add(zone);
            RefreshObjectives();
        }
    }
}