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

package shortcuts

import (
	"os"
	"path/filepath"
	"strings"

	"github.com/linuxdeepin/dde-daemon/keybinding/util"
	wm "github.com/linuxdeepin/go-dbus-factory/com.deepin.wm"
	"github.com/linuxdeepin/go-lib/keyfile"
)

// 配置文件键名常量
const (
	kfKeyName       = "Name"   // 快捷键名称键
	kfKeyKeystrokes = "Accels" // 按键序列键
	kfKeyAction     = "Action" // 执行命令键
)

// CustomShortcut 表示用户自定义快捷键
type CustomShortcut struct {
	BaseShortcut
	manager *CustomShortcutManager // 所属管理器
	Cmd     string `json:"Exec"`   // 执行的命令
	wm      wm.Wm                  // 窗口管理器接口
}

// Marshal 序列化自定义快捷键为JSON字符串
func (cs *CustomShortcut) Marshal() (string, error) {
	cs.mu.Lock()
	defer cs.mu.Unlock()
	return util.MarshalJSON(cs)
}

// SaveKeystrokes 保存当前快捷键的按键设置
func (cs *CustomShortcut) SaveKeystrokes() error {
	section := cs.GetId()
	if _useWayland {
		ok, err := SetShortForWayland(cs, cs.wm)
		if !ok {
			return err
		}
	}
	csm := cs.manager
	csm.kfile.SetStringList(section, kfKeyKeystrokes, cs.getKeystrokesStrv())
	return csm.Save()
}

// 经过 Reset 重置后， 自定义快捷键的 keystrokes 被设置为空，始终返回 false
// 是为了另外计算改变的自定义快捷键项目。
func (cs *CustomShortcut) ReloadKeystrokes() bool {
	cs.setKeystrokes(nil)
	return false
}

// ShouldEmitSignalChanged 是否触发改变信号
func (cs *CustomShortcut) ShouldEmitSignalChanged() bool {
	return true
}

// Save 保存自定义快捷键的完整配置
func (cs *CustomShortcut) Save() error {
	section := cs.GetId()
	kfile := cs.manager.kfile
	kfile.SetString(section, kfKeyName, cs.Name)
	kfile.SetString(section, kfKeyAction, cs.Cmd)
	kfile.SetStringList(section, kfKeyKeystrokes, cs.getKeystrokesStrv())
	return cs.manager.Save()
}

// GetAction 获取快捷键对应的操作
func (cs *CustomShortcut) GetAction() *Action {
	_, err := os.Stat(cs.Cmd)
	if !os.IsNotExist(err) {
		if strings.HasSuffix(cs.Cmd, ".desktop") {
			return &Action{
				Type: ActionTypeDesktopFile,
				Arg:  cs.Cmd,
			}
		}
	}

	a := &Action{
		Type: ActionTypeExecCmd,
		Arg: &ActionExecCmdArg{
			Cmd: cs.Cmd,
		},
	}
	return a
}

// SetName 设置自定义快捷键名称
func (cs *CustomShortcut) SetName(name string) {
	cs.Name = name
	if cs.manager.pinyinEnabled {
		cs.nameBlocksInit = false
		cs.initNameBlocks()
	}
	logger.Debugf("Set name for shortcut %s to '%s'", cs.GetId(), name)
}

// CustomShortcutManager 管理用户自定义快捷键
type CustomShortcutManager struct {
	file          string             // 配置文件路径
	kfile         *keyfile.KeyFile   // 键值文件对象
	pinyinEnabled bool               // 是否启用拼音搜索
}

// newCustomShort 创建新的自定义快捷键对象
func newCustomShort(id, name, cmd string, keystrokes []string, wm wm.Wm, csm *CustomShortcutManager) *CustomShortcut {
	return &CustomShortcut{
		BaseShortcut: BaseShortcut{
			Id:         id,
			Type:       ShortcutTypeCustom,
			Name:       name,
			Keystrokes: ParseKeystrokes(keystrokes),
		},
		manager: csm,
		wm: wm,
		Cmd: cmd,
	}
}

// NewCustomShortcutManager 创建自定义快捷键管理器
func NewCustomShortcutManager(file string) *CustomShortcutManager {
	kfile := keyfile.NewKeyFile()
	err := kfile.LoadFromFile(file)
	if err != nil && !os.IsNotExist(err) {
		logger.Warning(err)
	}

	m := &CustomShortcutManager{
		file:  file,
		kfile: kfile,
	}
	return m
}

// List 列出所有自定义快捷键
func (csm *CustomShortcutManager) List() []Shortcut {
	kfile := csm.kfile
	sections := kfile.GetSections()
	ret := make([]Shortcut, 0, len(sections))
	for _, section := range sections {
		id := section
		name, _ := kfile.GetString(section, kfKeyName)
		cmd, _ := kfile.GetString(section, kfKeyAction)
		keystrokes, _ := kfile.GetStringList(section, kfKeyKeystrokes)

		shortcut := &CustomShortcut{
			BaseShortcut: BaseShortcut{
				Id:         id,
				Type:       ShortcutTypeCustom,
				Keystrokes: ParseKeystrokes(keystrokes),
				Name:       name,
			},
			manager: csm,
			Cmd:     cmd,
		}

		ret = append(ret, shortcut)
	}
	return ret
}

// Save 保存所有自定义快捷键到文件
func (csm *CustomShortcutManager) Save() error {
	err := os.MkdirAll(filepath.Dir(csm.file), 0755)
	if err != nil {
		logger.Warning(err)
		return err
	}
	return csm.kfile.SaveToFile(csm.file)
}

// Add 添加新的自定义快捷键
func (csm *CustomShortcutManager) Add(name, action string, keystrokes []*Keystroke, wm wm.Wm) (Shortcut, error) {
	id := name
	csm.kfile.SetString(id, kfKeyName, name)
	csm.kfile.SetString(id, kfKeyAction, action)

	keystrokesStrv := make([]string, 0, len(keystrokes))
	for _, ks := range keystrokes {
		keystrokesStrv = append(keystrokesStrv, ks.String())
	}
	csm.kfile.SetStringList(id, kfKeyKeystrokes, keystrokesStrv)

	shortcut := &CustomShortcut{
		BaseShortcut: BaseShortcut{
			Id:         id,
			Type:       ShortcutTypeCustom,
			Keystrokes: keystrokes,
			Name:       name,
		},
		manager: csm,
		Cmd:     action,
		wm:      wm,
	}
	return shortcut, csm.Save()
}

// Delete 删除指定ID的自定义快捷键
func (csm *CustomShortcutManager) Delete(id string) error {
	if _, err := csm.kfile.GetSection(id); err != nil {
		logger.Warning("Failed to find custom shortcut section:", id, "error:", err)
		return err
	}

	csm.kfile.DeleteSection(id)
	return csm.Save()
}
