using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace NonaBGS.Journal {
    public class MissionCompletedEntry : Entry {
        private Dictionary<string, string> influences = new Dictionary<string, string>();
        private string readable_name = null;
        private bool readable_name_generated = false;
        private string name = null;
        private string commodity = null;
        private int count = 0;
        private int donated = 0;

        /* TODO: make this a file at some point for easier editing.
         */
        private static readonly Dictionary<string, string> humanreadable = new Dictionary<string, string> {
            { "Mission_AltruismCredits_name", "Donate Credits" },
            { "Mission_AltruismCredits_Bust_name", "Donate Credits (Bust)" },
            { "Mission_Collect_name", "Provide" },
            { "Mission_Collect_CivilLiberty_name", "Provide (Civil Liberty)" },
            { "Mission_Courier_Democracy_name", "Courier (Democracy)" },
            { "Mission_Courier_Elections_name", "Courier (Elections)" },
            { "Mission_Courier_name", "Courier" },
            { "Mission_Courier_RankEmp_name", "Courier (Empire)" },
            { "Mission_Delivery_Boom_name", "Delivery (Boom)" },
            { "Mission_Delivery_Retreat_name", "Delivery (Retreat)" },
            { "Mission_Delivery_name", "Delivery" },
            { "Mission_Delivery_Agriculture_name", "Delivery (Agriculture)" },
            { "Mission_Delivery_RankEmp_name", "Delivery (Imperial Rank)" },
            { "Mission_HackMegaship_name", "Hack Megaship" },
            { "Mission_Hack_BLOPS_Boom_name", "Hack Megaship (Black Ops)" },
            { "Mission_MassacreWing_name", "Massacre (Wing)" },
            { "Mission_Massacre_RankEmp_name", "Massacre (Imperial Navy)" },
            { "Mission_OnFoot_Collect_MB_name", "On Foot Collection" },
            { "Mission_OnFoot_Onslaught_MB_name", "On Foot Onslaught" },
            { "Mission_OnFoot_Onslaught_Offline_MB_name", "On Foot Onslaught (Offline)" },
            { "Mission_OnFoot_RebootRestore_MB_name", "On Foot Reboot/Restore" },
            { "Mission_OnFoot_Reboot_MB_name", "On Foot Reboot" },
            { "Mission_OnFoot_Salvage_MB_name", "On Foot Salvage" },
            { "Mission_Rescue_Planet_name", "Planet Rescue" },
            { "Mission_Salvage_name", "Salvage" },
            { "MISSION_Salvage_CivilUnrest_name", "Salvage (Civil Unrest)" },
            { "MISSION_Salvage_Illegal_name", "Salvage (Illegal)" },
            { "MISSION_Salvage_Retreat_name", "Salvage (Retreat)" },
            { "MISSION_Salvage_Expansion_name", "Salvage (Expansion)" },
            { "Mission_Salvage_RankEmp_name", "Salvage (Imperial Navy)" },
            { "MISSION_Scan_name", "Scan" },
        };

        protected override void Initialise() {
            MakeHumanReadableName();
            name = JSON.Value<string>("Name");
            if (JSON.ContainsKey("Commodity_Localised")) {
                commodity = JSON.Value<string>("Commodity_Localised");
            }
            if (JSON.ContainsKey("Count")) {
                count = JSON.Value<int>("Count");
            }
            if (JSON.ContainsKey("Donated")) {
                donated = JSON.Value<int>("Donated");
            }
        }

        public string Name => name;
        public string Commodity => commodity;
        public int Count => count;

        private void MakeHumanReadableName() {
            if (readable_name != null && readable_name.Length > 0) {
                return;
            }

            if (Name == null) {
                return;
            }

            StringBuilder builder;

            if (humanreadable.ContainsKey(Name)) {
                builder = new StringBuilder(humanreadable[Name]);
                readable_name_generated = false;
            } else {
                builder = new StringBuilder(Name);
                builder.Replace("Mission_", "");
                builder.Replace("_name", "");
                builder.Replace("_MB", "");
                builder.Replace('_', ' ');
                builder.Replace("Illegal", " (Illegal)");
                builder.Replace("OnFoot", "On Foot");
                builder.Replace(" BS", "");
                builder.Replace("HackMegaship", "Hack Megaship");
                builder.Replace("Boom", "");
                builder.Replace("RebootRestore", "Reboot/Restore");
                builder.Replace("CivilLiberty", "");
                readable_name_generated = true;
            }

            if (count > 0 && commodity != null) {
                builder.AppendFormat(" ({0} {1})", count, commodity);
            }

            if (donated > 0) {
                builder.AppendFormat(" ({0})", Credits.FormatCredits(donated));
            }

            readable_name = builder.ToString().Trim();
        }

        public string HumanReadableName {
            get {
                MakeHumanReadableName();
                return readable_name;
            }
        }

        public bool HumanReadableNameWasGenerated {
            get {
                MakeHumanReadableName();
                return readable_name_generated;
            }
        }

        public string GetInfluenceForFaction(string faction) {
            if (influences.ContainsKey(faction)) {
                return influences[faction];
            }

            var effects = JSON.Value<JArray>("FactionEffects");
            foreach (var effect in effects.Children<JObject>()) {
                if (effect.GetValue("Faction").ToString() != faction) {
                    continue;
                }
                    
                var influence = effect.Value<JArray>("Influence");
                if (influence == null || influence.Count == 0) {
                    // No influence reward, happens on courier missions sometimes.
                    // There is always one point of rep, even if the mission won't state it
                    influences.Add(faction, "+");
                }
                
                foreach (var infl in influence.Children<JObject>()) {
                    infl.TryGetValue("Influence", out JToken result);
                    if (result != null && result.Type == JTokenType.String) {
                        influences.Add(faction, result.ToString());
                        return result.ToString();
                    }
                }
            }

            return "";
        }
    }
}