using System;
using System.Drawing;
using TweetDuck.Browser.Data;
using TweetLib.Core.Features.Plugins.Config;
using TweetLib.Core.Serialization.Converters;
using TweetLib.Core.Systems.Configuration;
using TweetLib.Core.Utils;

namespace TweetDuck.Configuration{
    sealed class ConfigManager : IConfigManager{
        public UserConfig User { get; }
        public SystemConfig System { get; }
        public PluginConfig Plugins { get; }
        
        public event EventHandler ProgramRestartRequested;

        private readonly FileConfigInstance<UserConfig> infoUser;
        private readonly FileConfigInstance<SystemConfig> infoSystem;
        private readonly PluginConfigInstance<PluginConfig> infoPlugins;

        private readonly IConfigInstance<BaseConfig>[] infoList;

        public ConfigManager(){
            User = new UserConfig(this);
            System = new SystemConfig(this);
            Plugins = new PluginConfig(this);
            
            infoList = new IConfigInstance<BaseConfig>[]{
                infoUser = new FileConfigInstance<UserConfig>(Program.UserConfigFilePath, User, "program options"),
                infoSystem = new FileConfigInstance<SystemConfig>(Program.SystemConfigFilePath, System, "system options"),
                infoPlugins = new PluginConfigInstance<PluginConfig>(Program.PluginConfigFilePath, Plugins)
            };

            // TODO refactor further

            infoUser.Serializer.RegisterTypeConverter(typeof(WindowState), WindowState.Converter);

            infoUser.Serializer.RegisterTypeConverter(typeof(Point), new SingleTypeConverter<Point>{
                ConvertToString = value => $"{value.X} {value.Y}",
                ConvertToObject = value => {
                    int[] elements = StringUtils.ParseInts(value, ' ');
                    return new Point(elements[0], elements[1]);
                }
            });
            
            infoUser.Serializer.RegisterTypeConverter(typeof(Size), new SingleTypeConverter<Size>{
                ConvertToString = value => $"{value.Width} {value.Height}",
                ConvertToObject = value => {
                    int[] elements = StringUtils.ParseInts(value, ' ');
                    return new Size(elements[0], elements[1]);
                }
            });
        }

        public void LoadAll(){
            infoUser.Load();
            infoSystem.Load();
            infoPlugins.Load();
        }

        public void SaveAll(){
            infoUser.Save();
            infoSystem.Save();
            infoPlugins.Save();
        }

        public void ReloadAll(){
            infoUser.Reload();
            infoSystem.Reload();
            infoPlugins.Reload();
        }

        void IConfigManager.TriggerProgramRestartRequested(){
            ProgramRestartRequested?.Invoke(this, EventArgs.Empty);
        }

        IConfigInstance<BaseConfig> IConfigManager.GetInstanceInfo(BaseConfig instance){
            Type instanceType = instance.GetType();
            return Array.Find(infoList, info => info.Instance.GetType() == instanceType); // TODO handle null
        }
    }
}