using System.IO;
using PCL.Core.App;
using PCL.Core.App.Configuration;
using PCL.Core.App.Localization;
using PCL.Core.Utils.OS;

namespace PCL
{
    public class CustomEvent
    {
        public EventType Type { get; set; } = EventType.None;
        public string Data { get; set; } = string.Empty;

        public CustomEvent() { }

        public CustomEvent(EventType type, string data)
        {
            Type = type;
            Data = data;
        }

        public void Raise() => Raise(Type, Data);

        /// <summary>
        /// 静态入口：根据 EventType 分发给对应的 action 执行。
        /// </summary>
        public static void Raise(EventType type, string arg)
        {
            if (type == EventType.None) return;
            ModBase.Log($"[Control] 执行自定义事件: {type}, {arg}");

            try
            {
                if (ActionMap.TryGetValue(type, out var action))
                    action(arg, type);
                else
                    ModMain.MyMsgBox(
                        Lang.Text("Event.Error.UnknownType", type.ToString()),
                        Lang.Text("Event.Error.Title"));
            }
            catch (Exception ex)
            {
                ModBase.Log(
                    ex,
                    Lang.Text("Event.Error.ExecutionFailed", type, arg),
                    ModBase.LogLevel.Msgbox,
                    userSummary: Lang.Text("Event.Error.ExecutionFailed", type, arg));
            }
        }

        public static string GetCustomVariable(string name, string defaultValue = "") =>
            States.CustomVariables.GetValueOrDefault(name, defaultValue);

        /// <summary>
        /// 将 arg 按 '|' 分割为参数数组，空串统一返回 [""]。
        /// </summary>
        private static string[] SplitArgs(string arg) => arg.Split('|');

        /// <summary>
        /// 将 \\n 替换为 Windows 换行符 \r\n。
        /// </summary>
        private static string FixNewlines(string s) => s.Replace("\\n", "\r\n");

        /// <summary>
        /// 禁止自定义主页写入的高危设置黑名单
        /// </summary>
        private static readonly HashSet<string> SecuritySensitiveSettingKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
        { 
            "LaunchAdvanceRun", 
            "VersionAdvanceRun"
        };
        
        /// <summary>
        /// EventType → 执行逻辑 的字典映射，O(1) 分发。
        /// </summary>
        private static readonly Dictionary<EventType, Action<string, EventType>> ActionMap = new()
        {
            [EventType.OpenUrl] = _OpenUrl,
            [EventType.OpenFile] = _OpenFileOrCommand,
            [EventType.ExecuteCommand] = _OpenFileOrCommand,
            [EventType.LaunchGame] = _LaunchGame,
            [EventType.CopyText] = _CopyText,
            [EventType.RefreshHomepage] = _Refresh,
            [EventType.RefreshPage] = _Refresh,
            [EventType.DailyFortune] = _DailyFortune,
            [EventType.ClearTrash] = _ClearTrash,
            [EventType.ShowDialog] = _ShowDialog,
            [EventType.ShowHint] = _ShowHint,
            [EventType.SwitchPage] = _SwitchPage,
            [EventType.ImportModpack] = _ModpackInstall,
            [EventType.InstallModpack] = _ModpackInstall,
            [EventType.DownloadFile] = _DownloadFile,
            [EventType.ModifySetting] = _WriteSetting,
            [EventType.WriteSetting] = _WriteSetting,
            [EventType.ModifyVariable] = _WriteVariable,
            [EventType.WriteVariable] = _WriteVariable,
            [EventType.OpenHelp] = (_, __) => ModBase.OpenWebsite("https://docs.pclc.cc/ce"),
        };

        /// <summary>
        /// 打开网页。校验 https?:// 前缀，非 file 协议。
        /// </summary>
        private static void _OpenUrl(string arg, EventType type)
        {
            arg = arg.Replace('\\', '/');
            if (!arg.Contains("://") || arg.StartsWithF("file", true))
            {
                ModMain.MyMsgBox(Lang.Text("Event.Error.UrlRequired"), Lang.Text("Event.Error.Title"));
                return;
            }
            HintService.Hint(Lang.Text("Event.OpenUrl.Opening", arg));
            ModBase.RunInThread(() => ModBase.OpenWebsite(arg));
        }

        /// <summary>
        /// 打开文件 / 执行命令。复用 GetAbsoluteUrls 解析路径后 ProcessInterop.Start 启动。
        /// </summary>
        private static void _OpenFileOrCommand(string arg, EventType type)
        {
            var args = SplitArgs(arg);
            ModBase.RunInThread(() =>
            {
                try
                {
                    var urls = GetAbsoluteUrls(args[0], type);
                    if (!EventSafetyConfirm($"{urls[0]}{(args.Length >= 2 ? " " + args[1] : "")}"))
                        return;
                    ProcessInterop.Start(urls[0], args.Length >= 2 ? args[1] : "");
                }
                catch (Exception ex)
                {
                    ModBase.Log(
                        ex,
                        Lang.Text("Event.Error.ExecutionFailed", type, arg),
                        ModBase.LogLevel.Msgbox,
                        userSummary: Lang.Text("Event.Error.ExecutionFailed", type, arg));
                }
            });
        }

        /// <summary>
        /// 启动游戏。支持 \current 指代当前选中实例，可选 ServerIp。
        /// </summary>
        private static void _LaunchGame(string arg, EventType type)
        {
            var args = SplitArgs(arg);
            if (args[0] == "\\current")
            {
                if (ModInstanceList.McMcInstanceSelected is null)
                    throw new InvalidOperationException(Lang.Text("Event.LaunchGame.SelectVersion"));
                args[0] = ModInstanceList.McMcInstanceSelected.Name;
            }
            ModBase.RunInUi(() =>
            {
                var launchOptions = new ModLaunch.McLaunchOptions
                {
                    ServerIp = args.Length >= 2 ? args[1] : null,
                    instance = new McInstance(args[0])
                };
                if (ModLaunch.McLaunchStart(launchOptions))
                    HintService.Hint(Lang.Text("Event.LaunchGame.Starting", args[0]));
            });
        }

        /// <summary>
        /// 复制文本到剪贴板。
        /// </summary>
        private static void _CopyText(string arg, EventType _) => ModBase.ClipboardSet(arg);

        /// <summary>
        /// 刷新主页 / 刷新当前页面。要求当前 pageRight 实现 IRefreshable。
        /// </summary>
        private static void _Refresh(string arg, EventType _)
        {
            if (ModMain.frmMain?.pageRight is IRefreshable refreshable)
            {
                ModBase.RunInUiWait(() => refreshable.Refresh());
                if (string.IsNullOrEmpty(arg))
                    HintService.Hint(Lang.Text("Event.Refresh.Success"), HintType.Success);
            }
            else
                HintService.Hint(Lang.Text("Event.Refresh.NotSupported"), HintType.Error);
        }

        /// <summary>
        /// 今日人品。
        /// </summary>
        private static void _DailyFortune(string _, EventType __) => PageToolsTest.Jrrp();

        /// <summary>
        /// 清理垃圾。异步执行 RubbishClear。
        /// </summary>
        private static void _ClearTrash(string _, EventType __) =>
            ModBase.RunInThread(PageToolsTest.RubbishClear);

        /// <summary>
        /// 弹出消息框。参数：Title|Content[|ButtonText]。
        /// </summary>
        private static void _ShowDialog(string arg, EventType type)
        {
            var args = SplitArgs(arg);
            if (args.Length == 1)
                throw new ArgumentException(Lang.Text("Event.Error.MissingArgs", type.ToString(), "Title|Content"));
            ModMain.MyMsgBox(
                FixNewlines(args[1]),
                FixNewlines(args[0]),
                args.Length > 2 ? args[2] : Lang.Text("Common.Action.Confirm"));
        }

        /// <summary>
        /// 弹出提示条。参数：Message[|HintType]（HintType = Info / Success / Error，兼容旧版 Finish / Critical）。
        /// </summary>
        private static void _ShowHint(string arg, EventType _)
        {
            var args = SplitArgs(arg);
            var hintType = args.Length == 1
                ? HintType.Info
                : (HintType)Enum.Parse(typeof(HintType), NormalizeHintTypeName(args[1]), true);
            HintService.Hint(FixNewlines(args[0]), hintType);
        }

        /// <summary>
        /// 将旧版 HintType 名称映射到当前名称，保持对旧主页的兼容。
        /// </summary>
        private static string NormalizeHintTypeName(string name) => name.ToLowerInvariant() switch
        {
            "finish" => nameof(HintType.Success),
            "critical" => nameof(HintType.Error),
            _ => name
        };

        /// <summary>
        /// 切换页面。参数：PageType[|PageSubType]。
        /// </summary>
        private static void _SwitchPage(string arg, EventType _)
        {
            var args = SplitArgs(arg);
            ModBase.RunInUi(() =>
            {
                var page = (FormMain.PageType)Enum.Parse(typeof(FormMain.PageType), args[0], true);
                var sub = args.Length == 1
                    ? FormMain.PageSubType.Default
                    : (FormMain.PageSubType)Enum.Parse(typeof(FormMain.PageSubType), args[1], true);
                ModMain.frmMain?.PageChange(page, sub);
            });
        }

        /// <summary>
        /// 导入 / 安装整合包。触发 ModModpack.ModpackInstall()。
        /// </summary>
        private static void _ModpackInstall(string _, EventType __) =>
            ModBase.RunInUi(ModModpack.ModpackInstall);

        /// <summary>
        /// 下载文件。参数：Url[|SavePath[|FileName]]，校验 http/https 前缀并弹安全确认。
        /// </summary>
        private static void _DownloadFile(string arg, EventType _)
        {
            var args = SplitArgs(arg);
            args[0] = args[0].Replace('\\', '/');
            if (!args[0].StartsWithF("http://", true) && !args[0].StartsWithF("https://", true))
            {
                ModMain.MyMsgBox(Lang.Text("Event.Error.DownloadUrlRequired"), Lang.Text("Event.Error.Title"));
                return;
            }
            if (!EventSafetyConfirm(Lang.Text("Event.Download.Confirm", args[0])))
                return;

            try
            {
                PageToolsTest.StartCustomDownload(args[0],
                    args.Length >= 2 ? args[1] : ModBase.GetFileNameFromPath(args[0]),
                    args.Length >= 3 ? args[2] : null);
            }
            catch
            {
                PageToolsTest.StartCustomDownload(args[0], Lang.Text("Common.State.Unknown"));
            }
        }

        /// <summary>
        /// 写入 / 修改设置。参数：SettingName|Value。
        /// </summary>
        private static void _WriteSetting(string arg, EventType type)
        {
            var args = SplitArgs(arg);
            if (args.Length == 1)
                throw new ArgumentException(Lang.Text("Event.Error.MissingArgs", type.ToString(), "SettingName|Value"));
            if (ConfigService.TryGetConfigItemNoType(args[0], out var item) && item.Source != ConfigSource.SharedEncrypt)
            {
                if (!CanWriteSettingFromCustomEvent(args[0]))
                    return;
                item.SetValueNoType(args[1], ModInstanceList.McMcInstanceSelected?.PathInstance);
            }
            if (args.Length == 2)
                HintService.Hint(Lang.Text("Event.Setting.Written", args[0], args[1]), HintType.Success);
        }
        private static bool CanWriteSettingFromCustomEvent(string key)
        {
            if (!SecuritySensitiveSettingKeys.Contains(key))
                return true;
            ModBase.Log($"[Control] 已阻止自定义事件写入高危设置：{key}", ModBase.LogLevel.Developer);
            HintService.Hint(Lang.Text("Event.Safety.DangerousSettingBlocked", key), HintType.Error);
            return false;
        }

        /// <summary>
        /// 写入 / 修改自定义变量。参数：VariableName|Value。
        /// </summary>
        private static void _WriteVariable(string arg, EventType type)
        {
            var args = SplitArgs(arg);
            if (args.Length == 1)
                throw new ArgumentException(Lang.Text("Event.Error.MissingArgs", type.ToString(), "VariableName|Value"));
            States.CustomVariables[args[0]] = args[1];
            States.CustomVariables = States.CustomVariables; // 触发 ConfigPropertyChanged
            if (args.Length == 2)
                HintService.Hint(Lang.Text("Event.Variable.Written", args[0], args[1]), HintType.Success);
        }

        public static string[] GetAbsoluteUrls(string relativeUrl, EventType type)
        {
            relativeUrl = relativeUrl.Replace('/', '\\').ToLower().TrimStart('\\');
            var pclDir = Path.Combine(Basics.ExecutableDirectory, "PCL");

            if (relativeUrl.Contains(":\\"))
            {
                ModBase.Log($"[Control] 自定义事件中由绝对路径 {type}: {relativeUrl}");
                return [relativeUrl, pclDir];
            }
            if (File.Exists(Path.Combine(pclDir, relativeUrl)))
            {
                var fullPath = Path.Combine(pclDir, relativeUrl);
                var resolved = Path.GetFullPath(fullPath);
                if (!resolved.StartsWith(pclDir, StringComparison.OrdinalIgnoreCase))
                    throw new UnauthorizedAccessException(Lang.Text("Event.Error.FileNotFound", relativeUrl));
                ModBase.Log($"[Control] 自定义事件中由相对 PCL 文件夹的路径 {type}: {fullPath}");
                return [fullPath, pclDir];
            }
            if (type is EventType.OpenFile or EventType.ExecuteCommand)
            {
                ModBase.Log($"[Control] 自定义事件中直接 {type}: {relativeUrl}");
                return [relativeUrl, pclDir];
            }
            throw new FileNotFoundException(Lang.Text("Event.Error.FileNotFound", relativeUrl), relativeUrl);
        }

        /// <summary>
        /// 安全确认对话框。已由用户勾选"不再询问"时跳过。
        /// </summary>
        private static bool EventSafetyConfirm(string message)
        {
            if (States.Hint.HomepageCommand)
                return true;

            return ModMain.MyMsgBox(
                Lang.Text("Event.Safety.ConfirmMessage", message),
                Lang.Text("Event.Safety.Title"),
                Lang.Text("Common.Action.Continue"),
                Lang.Text("Event.Safety.ContinueAlways"),
                Lang.Text("Common.Action.Cancel")) switch
            {
                1 => true,
                2 => States.Hint.HomepageCommand = true,
                _ => false,
            };
        }
    }
}
