using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using ImGuiNET;
using skyscraper5.Skyscraper;
using skyscraper5.Skyscraper.IO.TunerInterface;
using skyscraper5.Skyscraper.Scraper.Storage;

namespace SDL2Demo.Forms
{
    internal class ConfigureTunerFactoryWindow : IRenderable
    {
        private int tunerFactoryId;
        private readonly List<Setting> settings;

        public Ini Ini { get; }
        public ReadOnlyCollection<KeyValuePair<TunerFactoryIdAttribute, ITunerFactory>> TunerFactories { get; }

        public ConfigureTunerFactoryWindow(Ini ini, ReadOnlyCollection<KeyValuePair<TunerFactoryIdAttribute, ITunerFactory>> tunerFactories)
        {
            Ini = ini;
            TunerFactories = tunerFactories;
            Closed = false;
            tunerFactoryId = ini.ReadValue("startup", "tunerFactory", 0);
            settings = new List<Setting>();

            foreach (KeyValuePair<TunerFactoryIdAttribute, ITunerFactory> keyValuePair in TunerFactories)
            {
                PropertyInfo[] propertyInfos = keyValuePair.Value.GetType().GetProperties();
                foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    Setting s = new Setting();
                    s.IniKey = keyValuePair.Key.Id;
                    s.SettingName = propertyInfo.Name;
                    switch (propertyInfo.PropertyType.Name)
                    {
                        case nameof(String):
                            s.SettingMode = 1;
                            s.StringValue = ini.ReadValue(String.Format("tunerFactory{0}", s.IniKey), s.SettingName, "");
                            break;
                        case nameof(Int32):
                            s.SettingMode = 2;
                            s.IntValue = ini.ReadValue(String.Format("tunerFactory{0}", s.IniKey), s.SettingName, 0);
                            break;
                        default:
                            throw new NotImplementedException(propertyInfo.PropertyType.Name);
                    }

                    settings.Add(s);
                }
            }
        }

        internal class Setting
        {
            public Setting()
            {
                UiGuid = Guid.NewGuid().ToString();
            }

            public string UiGuid { get; set; }

            public long IniKey { get; set; }
            public string SettingName { get; set; }
            public int SettingMode { get; set; }
            public int IntValue;

            public string StringValue;

            public bool Validate()
            {
                switch (SettingMode)
                {
                    case 1:
                        return !string.IsNullOrEmpty(StringValue) && !string.IsNullOrWhiteSpace(StringValue);
                    case 2:
                        return true;
                    default:
                        throw new NotImplementedException(String.Format("Setting mode {0}", SettingMode));
                }
            }
        }

        private void Save()
        {
            Ini.WriteValue("startup", "tunerFactory", tunerFactoryId);
            foreach (Setting setting in settings)
            {
                switch (setting.SettingMode)
                {
                    case 1:
                        Ini.WriteValue(String.Format("tunerFactory{0}", setting.IniKey), setting.SettingName, setting.StringValue);
                        break;
                    case 2:
                        Ini.WriteValue(String.Format("tunerFactory{0}", setting.IniKey), setting.SettingName, setting.IntValue);
                        break;
                    default:
                        throw new NotImplementedException(String.Format("Setting mode {0}", setting.SettingMode));
                }
            }

            Ini.Export(new FileInfo("skyscraper5.ini"));

            if (HasChanges)
                RequireRestart = true;
            HasChanges = false;

        }

        public bool RequireRestart { get; set; }

        public bool HasChanges { get; set; }

        private bool CanApply()
        {
            foreach (Setting setting in settings.Where(x => x.IniKey == tunerFactoryId))
            {
                if (!setting.Validate())
                {
                    return false;
                }
            }
            return true;
        }

        public void Render()
        {
            ImGuiWindowFlags flags = ImGuiWindowFlags.None;
            if (HasChanges)
                flags |= ImGuiWindowFlags.UnsavedDocument;

            bool pOpen = true;
            ImGui.Begin("Configure Tuner Factory", ref pOpen, flags);

            foreach (KeyValuePair<TunerFactoryIdAttribute, ITunerFactory> keyValuePair in TunerFactories)
            {
                if (ImGui.RadioButton(keyValuePair.Key.DisplayName, ref tunerFactoryId, keyValuePair.Key.Id))
                {
                    HasChanges = true;
                }

                ImGui.BeginTable(keyValuePair.Key.TemporaryUUID, 2);

                foreach (Setting setting in settings.Where(x => x.IniKey == keyValuePair.Key.Id))
                {
                    ImGui.TableNextRow();
                    ImGui.TableSetColumnIndex(0);
                    ImGui.Text(setting.SettingName);
                    ImGui.TableSetColumnIndex(1);
                    ImGui.PushID(setting.UiGuid);
                    switch (setting.SettingMode)
                    {
                        case 1:
                            if (ImGui.InputText("", ref setting.StringValue, 255))
                                HasChanges = true;
                            break;
                        case 2:
                            if (ImGui.InputInt("", ref setting.IntValue,1,10))
                                HasChanges = true;
                            break;
                        default:
                            throw new NotImplementedException(String.Format("Setting mode {0}", setting.SettingMode));
                    }
                    ImGui.PopID();
                }
                ImGui.EndTable();
            }

            ImGui.Separator();

            bool canApply = CanApply();
            ImGui.BeginDisabled(!canApply);
            if (ImGui.Button("OK"))
            {
                Save();
                Closed = true;
            }
            ImGui.EndDisabled();

            ImGui.SameLine();
            if (ImGui.Button("Cancel"))
            {
                Closed = true;
            }

            ImGui.SameLine();
            ImGui.BeginDisabled(!canApply);
            if (ImGui.Button("Apply"))
            {
                Save();
            }
            ImGui.EndDisabled();


            ImGui.End();
            if (!pOpen)
                Closed = true;
        }

        public bool Closed { get; set; }
    }
}
