using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using TweetLib.Core.Serialization;
using TweetLib.Core.Serialization.Converters;

namespace TweetDuck.Core.Other.Analytics{
    [SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Local")]
    sealed class AnalyticsFile{
        private static readonly FileSerializer<AnalyticsFile> Serializer = new FileSerializer<AnalyticsFile>();

        static AnalyticsFile(){
            Serializer.RegisterTypeConverter(typeof(DateTime), new SingleTypeConverter<DateTime>{
                ConvertToString = value => value.ToBinary().ToString(),
                ConvertToObject = value => DateTime.FromBinary(long.Parse(value))
            });

            Serializer.RegisterTypeConverter(typeof(Counter), new SingleTypeConverter<Counter>{
                ConvertToString = value => value.Value.ToString(),
                ConvertToObject = value => int.Parse(value)
            });
        }

        public static readonly AnalyticsFile Dummy = new AnalyticsFile();

        // STATE PROPERTIES
        
        public DateTime LastDataCollection  { get; set; } = DateTime.MinValue;
        public string LastCollectionVersion { get; set; } = null;
        public string LastCollectionMessage { get; set; } = null;

        // USAGE DATA

        public Counter OpenOptions { get; private set; } = 0;
        public Counter OpenPlugins { get; private set; } = 0;
        public Counter OpenAbout   { get; private set; } = 0;
        public Counter OpenGuide   { get; private set; } = 0;

        public Counter DesktopNotifications { get; private set; } = 0;
        public Counter SoundNotifications   { get; private set; } = 0;
        public Counter NotificationMutes    { get; private set; } = 0;
        
        public Counter BrowserContextMenus           { get; private set; } = 0;
        public Counter BrowserExtraMouseButtons      { get; private set; } = 0;
        public Counter NotificationContextMenus      { get; private set; } = 0;
        public Counter NotificationExtraMouseButtons { get; private set; } = 0;
        public Counter NotificationKeyboardShortcuts { get; private set; } = 0;

        public Counter BrowserReloads   { get; private set; } = 0;
        public Counter CopiedUsernames  { get; private set; } = 0;
        public Counter ViewedImages     { get; private set; } = 0;
        public Counter DownloadedImages { get; private set; } = 0;
        public Counter DownloadedVideos { get; private set; } = 0;
        public Counter UsedROT13        { get; private set; } = 0;

        public Counter TweetScreenshots { get; private set; } = 0;
        public Counter TweetDetails     { get; private set; } = 0;
        public Counter VideoPlays       { get; private set; } = 0;

        // END OF DATA

        public event EventHandler PropertyChanged;
        
        private readonly string file;
        
        private AnalyticsFile(string file){
            this.file = file;
        }

        private AnalyticsFile(){
            this.file = null;
        }

        private void SetupProperties(){
            foreach(Counter counter in GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(prop => prop.PropertyType == typeof(Counter)).Select(prop => (Counter)prop.GetValue(this))){
                counter.SetOwner(this);
            }
        }

        public void OnPropertyChanged(){
            PropertyChanged?.Invoke(this, EventArgs.Empty);
        }

        public void Save(){
            if (file == null){
                return;
            }

            try{
                Serializer.Write(file, this);
            }catch(Exception e){
                Program.Reporter.HandleException("Analytics File Error", "Could not save the analytics file.", true, e);
            }
        }
        
        public static AnalyticsFile Load(string file){
            AnalyticsFile config = new AnalyticsFile(file);
            
            try{
                Serializer.ReadIfExists(file, config);
            }catch(Exception e){
                Program.Reporter.HandleException("Analytics File Error", "Could not open the analytics file.", true, e);
            }
            
            config.SetupProperties();
            return config;
        }

        public interface IProvider{
            AnalyticsFile AnalyticsFile { get; }
        }

        public sealed class Counter{
            public int Value { get; private set; }

            private AnalyticsFile owner;

            public Counter(int value){
                this.Value = value;
            }

            public void SetOwner(AnalyticsFile owner){
                this.owner = owner;
            }

            public void Trigger(){
                ++Value;
                owner?.OnPropertyChanged();
            }

            public static implicit operator int(Counter counter) => counter.Value;
            public static implicit operator Counter(int value) => new Counter(value);
        }
    }
}