// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

package shortcuts

import (
	"encoding/json"
	"io/ioutil"
	"path"
	"sync"

	dutils "github.com/linuxdeepin/go-lib/utils"
)

// system_shortcut.go 处理系统快捷键配置和操作
// 定义系统级快捷键及其对应的操作命令

const (
	// 系统操作配置文件路径（位于'/usr/share'或'/usr/local/share'）
	systemActionsFile   = "dde-daemon/keybinding/system_actions.json"
	// 截图命令前缀
	screenshotCmdPrefix = "dbus-send --print-reply --dest=com.deepin.Screenshot /com/deepin/Screenshot com.deepin.Screenshot."
)

// SystemShortcut 表示系统快捷键
// 继承自GSettingsShortcut，用于处理系统级快捷键的配置和操作
type SystemShortcut struct {
	*GSettingsShortcut // 继承GSettingsShortcut
	arg *ActionExecCmdArg // 执行命令参数
}

// SetName 设置快捷键名称（系统快捷键不支持修改名称）
func (ss *SystemShortcut) SetName(name string) error {
	return ErrOpNotSupported
}

// GetAction 获取系统快捷键对应的操作
func (ss *SystemShortcut) GetAction() *Action {
	return &Action{
		Type: ActionTypeExecCmd, // 操作类型：执行命令
		Arg:  ss.arg,            // 命令参数
	}
}

// SetAction 设置系统快捷键的操作
// 只支持设置执行命令类型的操作
func (ss *SystemShortcut) SetAction(newAction *Action) error {
	if newAction == nil {
		return ErrNilAction
	}
	if newAction.Type != ActionTypeExecCmd {
		return ErrInvalidActionType
	}

	arg, ok := newAction.Arg.(*ActionExecCmdArg)
	if !ok {
		return ErrTypeAssertionFail
	}
	ss.arg = arg
	return nil
}

// 用于缓存系统操作配置
var loadSysActionsFileOnce sync.Once
var actionsCache *actionHandler

// GetSystemActionCmd 获取系统快捷键对应的命令
// id: 快捷键ID
func GetSystemActionCmd(id string) string {
	return getSystemActionCmd(id)
}

// getSystemActionCmd 内部实现获取系统快捷键命令
func getSystemActionCmd(id string) string {
	logger.Debug("Getting system action command for id:", id)

	// 使用sync.Once确保只加载一次配置文件
	loadSysActionsFileOnce.Do(func() {
		file := getSystemActionsFile()
		actions, err := loadSystemActionsFile(file)
		if err != nil {
			logger.Warning("failed to load system actions file:", err)
			return
		}
		actionsCache = actions
	})

	// 优先从缓存中获取命令
	if actionsCache != nil {
		if cmd, ok := actionsCache.getCmd(id); ok {
			logger.Debug("Found command in cache for id:", id, "cmd:", cmd)
			return cmd
		}
	}

	// Wayland环境特殊处理锁屏命令
	if id == "lock-screen" && _useWayland {
		id = "lock-screen-wayland"
	}

	// 从默认命令映射中获取
	return defaultSysActionCmdMap[id]
}

// defaultSysActionCmdMap 系统快捷键默认命令映射
// key: 快捷键ID, value: 对应的命令
var defaultSysActionCmdMap = map[string]string{
	"launcher":       "dbus-send --print-reply --dest=com.deepin.dde.Launcher /com/deepin/dde/Launcher com.deepin.dde.Launcher.Toggle", // 启动器
	"terminal":       "/usr/lib/deepin-daemon/default-terminal", // 终端
	"terminal-quake": "deepin-terminal --quake-mode", // 快速终端
	"lock-screen":    "originmap=$(setxkbmap -query | grep option | awk -F ' ' '{print $2}');/usr/bin/setxkbmap -option grab:break_actions&&/usr/bin/xdotool key XF86Ungrab&&dbus-send --print-reply --dest=com.deepin.dde.lockFront /com/deepin/dde/lockFront com.deepin.dde.lockFront.Show&&/usr/bin/setxkbmap -option $originmap", // 锁屏
	// Wayland环境不能设置XF86Ungrab，否则会导致Bug-224309
	"lock-screen-wayland":    "originmap=$(setxkbmap -query | grep option | awk -F ' ' '{print $2}');/usr/bin/setxkbmap -option grab:break_actions&&dbus-send --print-reply --dest=com.deepin.dde.lockFront /com/deepin/dde/lockFront com.deepin.dde.lockFront.Show&&/usr/bin/setxkbmap -option $originmap", // Wayland锁屏
	"logout":                 "dbus-send --print-reply --dest=com.deepin.dde.shutdownFront /com/deepin/dde/shutdownFront com.deepin.dde.shutdownFront.Show", // 注销
	"deepin-screen-recorder": "dbus-send --print-reply --dest=com.deepin.ScreenRecorder /com/deepin/ScreenRecorder com.deepin.ScreenRecorder.stopRecord", // 屏幕录制
	"system-monitor":         "/usr/bin/deepin-system-monitor", // 系统监视器
	"color-picker":           "dbus-send --print-reply --dest=com.deepin.Picker /com/deepin/Picker com.deepin.Picker.Show", // 取色器
	// 截图操作:
	"screenshot":             screenshotCmdPrefix + "StartScreenshot", // 开始截图
	"screenshot-fullscreen":  screenshotCmdPrefix + "FullscreenScreenshot", // 全屏截图
	"screenshot-window":      screenshotCmdPrefix + "TopWindowScreenshot", // 窗口截图
	"screenshot-delayed":     screenshotCmdPrefix + "DelayScreenshot int64:5", // 延时截图
	"screenshot-ocr":         screenshotCmdPrefix + "OcrScreenshot", // OCR截图
	"screenshot-scroll":      screenshotCmdPrefix + "ScrollScreenshot", // 滚动截图
	"file-manager":           "/usr/lib/deepin-daemon/default-file-manager", // 文件管理器
	"disable-touchpad":       "gsettings set com.deepin.dde.touchpad touchpad-enabled false", // 禁用触摸板
	"wm-switcher":            "dbus-send --type=method_call --dest=com.deepin.WMSwitcher /com/deepin/WMSwitcher com.deepin.WMSwitcher.RequestSwitchWM", // 窗口管理器切换
	"turn-off-screen":        "sleep 0.5; xset dpms force off", // 关闭屏幕
	"notification-center":    "dbus-send --print-reply --dest=com.deepin.dde.osd /org/freedesktop/Notifications com.deepin.dde.Notification.Toggle", // 通知中心
	"clipboard":              "dbus-send --print-reply --dest=com.deepin.dde.Clipboard /com/deepin/dde/Clipboard com.deepin.dde.Clipboard.Toggle; dbus-send --print-reply --dest=com.deepin.dde.Launcher /com/deepin/dde/Launcher com.deepin.dde.Launcher.Hide", // 剪贴板
	"global-search":          "/usr/libexec/dde-daemon/keybinding/shortcut-dde-grand-search.sh", // 全局搜索
	"switch-next-kbd-layout": "dbus-send --print-reply --dest=com.deepin.daemon.Keybinding /com/deepin/daemon/InputDevice/Keyboard com.deepin.daemon.InputDevice.Keyboard.ToggleNextLayout", // 切换键盘布局
	"switch-monitors":        "dbus-send --print-reply --dest=com.deepin.dde.osd / com.deepin.dde.osd.ShowOSD string:SwitchMonitors", // 切换显示器
	// 其他命令
	"calculator": "/usr/bin/deepin-calculator", // 计算器
	"search":     "/usr/libexec/dde-daemon/keybinding/shortcut-dde-grand-search.sh", // 搜索
	"script":     "/usr/libexec/dde-daemon/keybinding/shortcut-dde-script.sh", // 脚本
}

// actionHandler 系统操作配置处理器
// 用于解析系统操作配置文件
type actionHandler struct {
	Actions []struct {
		Key    string `json:"Key"`    // 快捷键ID
		Action string `json:"Action"` // 对应命令
	} `json:"Actions"`
}

// getCmd 根据快捷键ID获取命令
func (a *actionHandler) getCmd(id string) (cmd string, ok bool) {
	for _, v := range a.Actions {
		if v.Key == id {
			return v.Action, true
		}
	}
	return "", false
}

// loadSystemActionsFile 加载系统操作配置文件
func loadSystemActionsFile(file string) (*actionHandler, error) {
	logger.Debug("Loading system actions file:", file)

	// #nosec G304
	content, err := ioutil.ReadFile(file)
	if err != nil {
		logger.Warningf("Failed to read system actions file %s: %v", file, err)
		return nil, err
	}

	var handler actionHandler
	err = json.Unmarshal(content, &handler)
	if err != nil {
		logger.Warningf("Failed to parse JSON from system actions file %s: %v", file, err)
		return nil, err
	}

	return &handler, nil
}

// getSystemActionsFile 获取系统操作配置文件路径
// 优先查找/usr/local/share，其次查找/usr/share
func getSystemActionsFile() string {
	var file = path.Join("/usr/local/share", systemActionsFile)
	if dutils.IsFileExist(file) {
		logger.Debugf("Found system actions file at: %s", file)
		return file
	}

	file = path.Join("/usr/share", systemActionsFile)
	if dutils.IsFileExist(file) {
		logger.Debugf("Found system actions file at: %s", file)
		return file
	}

	return ""
}
