using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Threading;
using PCL.Core.UI.Controls;
using PCL.Core.Utils;

using PCL.Core.App.Localization;
namespace PCL;

internal static class ModStyle
{
    // Partly generated by claude-sonnet-4-20250514
    public class TimerRun : Run, IDisposable
    {
        // 定时器事件
        public delegate void TimerTickDelegate(TimerRun sender);

        // 定义依赖属性
        public static readonly DependencyProperty UpdateIntervalProperty =
            DependencyProperty.Register(nameof(UpdateInterval), typeof(TimeSpan), typeof(TimerRun),
                new PropertyMetadata(TimeSpan.FromSeconds(1d)));

        private object _isDisposed = false;

        private DispatcherTimer _timer;

        public TimerRun(TimeSpan interval = default, bool autoStart = false)
        {
            _timer = new DispatcherTimer();
            _timer.Tick += _TimerTick;
            UpdateInterval = interval == default ? TimeSpan.FromSeconds(1d) : interval;
            AutoStart = autoStart;
            Loaded += OnLoaded;
            Unloaded += OnUnloaded;
        }

        private object _isTimerRunning => _timer is not null && _timer.IsEnabled;

        // UpdateInterval 属性
        public TimeSpan UpdateInterval
        {
            get => (TimeSpan)GetValue(UpdateIntervalProperty);
            set
            {
                if (value > TimeSpan.Zero) SetValue(UpdateIntervalProperty, value);
            }
        }

        public bool AutoStart { get; set; }

        public void Dispose()
        {
            if ((bool)_isDisposed)
                return;
            _isDisposed = true;
            // 资源释放
            _timer.Tick -= _TimerTick;
            _timer?.Stop();
            _timer = null;
        }

        // 属性变化处理
        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);
            if (ReferenceEquals(e.Property, UpdateIntervalProperty) && _timer is not null)
                _timer.Interval = UpdateInterval;
        }

        public event TimerTickDelegate? TimerTick;

        private void _TimerTick(object sender, EventArgs e)
        {
            TimerTick?.Invoke(this);
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            if (AutoStart)
                StartTimer();
        }

        private void OnUnloaded(object sender, RoutedEventArgs e)
        {
            StopTimer();
        }

        public void StartTimer()
        {
            if (Dispatcher is null)
            {
                ModBase.Log(
                    "[TimerRun] Dispatcher is null, unable to run",
                    ModBase.LogLevel.Critical,
                    userSummary: Lang.Text("Minecraft.Launch.Error.DispatcherUnavailable"));
                return;
            }

            if (!(bool)_isTimerRunning)
                _timer?.Start();
        }

        public void StopTimer()
        {
            if ((bool)_isTimerRunning)
                _timer?.Stop();
        }
    }

    public class MinecraftFormatter
    {
        private static readonly Dictionary<string, string> colorMap = new()
        {
            { "black", "0" }, { "dark_blue", "1" }, { "dark_green", "2" }, { "dark_aqua", "3" }, { "dark_red", "4" },
            { "dark_purple", "5" }, { "gold", "6" }, { "gray", "7" }, { "dark_gray", "8" }, { "blue", "9" },
            { "green", "a" }, { "aqua", "b" }, { "red", "c" }, { "light_purple", "d" }, { "yellow", "e" },
            { "white", "f" }
        };

        private static readonly Random random = new();

        private static readonly string randomChars =
            "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()_+-=[]{}|;:,.<>?/~";

        public static string ConvertToMinecraftFormat(JsonObject data)
        {
            var result = "";
            foreach (var item in data["extra"].AsArray())
                result += ProcessElement((JsonObject)item, new List<string>());
            return result.Replace("§§", "§");
        }

        private static string ProcessElement(JsonObject element, List<string> currentFormat)
        {
            var text = "";
            var formats = new List<string>(currentFormat);

            // 处理格式
            if (element.ContainsKey("bold") && element["bold"].ToObject<bool>()) formats.Add("l");

            if (element.ContainsKey("color"))
            {
                var color = element["color"].ToString();
                var colorCode = "f";
                if (colorMap.ContainsKey(color)) colorCode = colorMap[color];
                formats.Insert(0, colorCode); // 颜色代码在前
            }

            // 应用格式
            if (formats.Count > 0) text += "§" + string.Join("§", formats);

            // 添加文本内容
            if (element.ContainsKey("text")) text += element["text"].ToString();

            // 处理子元素
            if (element.ContainsKey("extra"))
                foreach (var child in element["extra"].AsArray())
                    text += ProcessElement((JsonObject)child, new List<string>(formats));

            return text;
        }

        /// <summary>
        ///     Minecraft 文本格式化代码，用于显示不同颜色的文本
        /// </summary>
        /// <param name="text">要格式化的文本</param>
        /// <param name="lab">控件</param>
        public static void SetColorfulTextLab(string text, TextBlock lab, bool isDarkMode = true)
        {
            if (lab is null)
            {
                ModBase.Log("[Style] SetColorfulTextLab: lab is null");
                return;
            }

            lab.Inlines.Clear();

            var hasItalicProperty = false; // 斜体
            var hasDeleteLineProperty = false; // 删除线
            var hasStrickThroughProperty = false; // 下划线
            var hasBlodProperty = false; // 粗体
            var isRandomText = false; // 随机文本模式

            var color = isDarkMode ? "#FFFFFF" : "#888888";
            var isColorCode = false;
            var curRun = new TimerRun();
            lab.Inlines.Add(curRun);

            // 用于存储需要随机化的文本段
            var randomTextRuns = new List<TimerRun>();

            foreach (var c in text)
            {
                if (c.ToString() == "§") // 下一字符是格式化代码
                {
                    isColorCode = true;
                    continue;
                }

                if (isColorCode)
                {
                    var prevColor = color;
                    if (!MotdRenderer.TryGetColorFromCode(c.ToString(), isDarkMode, out color))
                    {
                        color = prevColor; // out 会将 color 置为 null，统一恢复为之前的颜色
                        switch (c)
                        {
                            // 格式化代码
                            case 'k':
                            case 'K': // 随机字符
                            {
                                isRandomText = true;
                                // 开始新的Run用于随机文本
                                if (!string.IsNullOrEmpty(curRun.Text))
                                {
                                    curRun = new TimerRun();
                                    lab.Inlines.Add(curRun);
                                }

                                curRun.AutoStart = true;
                                randomTextRuns.Add(curRun);
                                break;
                            }
                            case 'l': // 粗体
                            {
                                hasBlodProperty = true;
                                break;
                            }
                            case 'o': // 斜体
                            {
                                hasItalicProperty = true;
                                break;
                            }
                            case 'n': // 下划线
                            {
                                hasStrickThroughProperty = true;
                                break;
                            }
                            case 'm': // 删除线
                            {
                                hasDeleteLineProperty = true;
                                break;
                            }
                            case 'r': // 重置
                            {
                                color = isDarkMode ? "#FFFFFF" : "#888888";
                                hasBlodProperty = false;
                                hasItalicProperty = false;
                                hasStrickThroughProperty = false;
                                hasDeleteLineProperty = false;
                                isRandomText = false;
                                break;
                            }
                        }
                    }

                    if (!string.IsNullOrEmpty(curRun.Text) && c.ToString() != "k" && c.ToString() != "K") // 遇到格式代码但是有文本，重开一个Run
                    {
                        curRun = new TimerRun();
                        lab.Inlines.Add(curRun);
                    }

                    curRun.Foreground = new SolidColorBrush(new ModBase.MyColor(color));
                    curRun.FontWeight = hasBlodProperty ? FontWeights.Bold : FontWeights.Normal;
                    curRun.FontStyle = hasItalicProperty ? FontStyles.Italic : FontStyles.Normal;
                    curRun.TextDecorations = hasStrickThroughProperty ? TextDecorations.Strikethrough : null;
                    curRun.TextDecorations = hasDeleteLineProperty ? TextDecorations.Underline : null;
                }
                else if (isRandomText)
                {
                    // 随机模式下，添加随机字符
                    curRun.Text += randomChars[random.Next(randomChars.Length)].ToString();
                }
                else
                {
                    curRun.Text += c.ToString();
                }

                if (isColorCode)
                    isColorCode = false;
            }

            // 设置定时器来更新随机文本
            if (randomTextRuns.Count > 0)
                foreach (var run in randomTextRuns)
                {
                    run.UpdateInterval = TimeSpan.FromMilliseconds(20d);
                    run.TimerTick += sender =>
                    {
                        if (!string.IsNullOrEmpty(sender.Text))
                        {
                            var sb = new StringBuilder();
                            for (int i = 0, loopTo = sender.Text.Length - 1; i <= loopTo; i++)
                                sb.Append(randomChars[random.Next(randomChars.Length)]);
                            sender.Text = sb.ToString();
                        }
                    };
                }
        }
    }
}