using MainShell.Filewritable;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace MXJM.FileWritable
{
    /// <summary>
    /// 通用的 JSON 可保存/加载基类，供任意需要持久化为 JSON 的类继承。
    /// 派生类可覆盖 Dir / FileName 指定保存位置与文件名。
    /// </summary>
    public abstract class JsonFileWritableBase
    {
        /// <summary>
        /// 存储目录，派生类可覆盖。默认为应用程序基目录。
        /// 标记为 JsonIgnore 避免被序列化到文件中。
        /// </summary>
        [JsonIgnore]
        public virtual string Dir => Paths.RecipeBasePath;
        [JsonIgnore]
        public virtual IgnorePropertiesResolver IgnorePropertiesResolver =>new IgnorePropertiesResolver(new string[] { "PropertyChangedDispatcher" });
        /// <summary>
        /// 文件名，派生类可覆盖。
        /// </summary>
        [JsonIgnore]
        public virtual string FileName => $"{GetType().Name}.json";

        /// <summary>
        /// 将当前实例以 JSON 形式保存到 Dir/FileName。
        /// </summary>
        public void Write()
        {
            var dir = Dir ?? string.Empty;
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);

            var path = Path.Combine(dir, FileName ?? "data.json");
            var settings = new JsonSerializerSettings
            {
                Formatting = Formatting.Indented,
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                ContractResolver = IgnorePropertiesResolver
            };
            var json = JsonConvert.SerializeObject(this, settings);
            File.WriteAllText(path, json);
        }
        public void Write(string path)
        {
            var dir = Path.GetDirectoryName(path);
            if (!string.IsNullOrWhiteSpace(dir) && !Directory.Exists(dir))
                Directory.CreateDirectory(dir);
            var settings = new JsonSerializerSettings
            {
                Formatting = Formatting.Indented,
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                ContractResolver= IgnorePropertiesResolver
            };
            var json = JsonConvert.SerializeObject(this, settings);
            File.WriteAllText(path, json);
        }
        /// <summary>
        /// 异步保存的简单封装。
        /// </summary>
        public Task WriteAsync(CancellationToken cancellationToken = default)
        {
            return Task.Run(() =>
            {
                cancellationToken.ThrowIfCancellationRequested();
                Write();
            }, cancellationToken);
        }

        /// <summary>
        /// 从指定路径读取 JSON 并填充到当前实例（使用 PopulateObject，集合使用 Replace）。
        /// 如果需要返回一个全新的对象，请使用静态 LoadFromFile&lt;T&gt; 方法。
        /// </summary>
        /// <param name="path">包含文件名的完整路径</param>
        public virtual void Read(string path)
        {
            if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
            {
                Write();
                return;
            }

            var json = File.ReadAllText(path);
            var settings = new JsonSerializerSettings
            {
                ObjectCreationHandling = ObjectCreationHandling.Replace,
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore
            };
            JsonConvert.PopulateObject(json, this, settings);
        }

        /// <summary>
        /// 从默认位置（Dir + FileName）读取。
        /// </summary>
        public virtual void Read()
        {
            var path = Path.Combine(Dir ?? string.Empty, FileName ?? string.Empty);
            Read(path);
        }

        /// <summary>
        /// 静态：从指定文件反序列化为新对象（若需要完整新实例，请使用此方法）。
        /// </summary>
        public static T LoadFromFile<T>(string path) where T : class
        {
            if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
                return null;
            var json = File.ReadAllText(path);
            return JsonConvert.DeserializeObject<T>(json);
        }

        /// <summary>
        /// 静态：将任意对象保存到指定文件（路径自动创建）。
        /// </summary>
        public static void SaveToFile<T>(T obj, string path)
        {
            if (obj == null) throw new ArgumentNullException(nameof(obj));
            if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullException(nameof(path));

            var dir = Path.GetDirectoryName(path);
            if (!string.IsNullOrWhiteSpace(dir) && !Directory.Exists(dir))
                Directory.CreateDirectory(dir);

            var settings = new JsonSerializerSettings
            {
                Formatting = Formatting.Indented,
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore
            };
            var json = JsonConvert.SerializeObject(obj, settings);
            File.WriteAllText(path, json);
        }
    }
}