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

package audio

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

	"github.com/linuxdeepin/go-lib/xdg/basedir"
)

// PortConfig 端口配置结构体
// 存储单个音频端口的配置信息
type PortConfig struct {
	Name           string  // 端口名称
	Enabled        bool    // 是否启用
	Volume         float64 // 音量值
	IncreaseVolume bool    // 是否启用音量增强
	Balance        float64 // 声道平衡值
	ReduceNoise    bool    // 是否启用降噪
	Mute           bool    // 静音改为全局，此配置废弃
}

// CardConfig 声卡配置结构体
// 存储单个声卡的配置信息
type CardConfig struct {
	Name  string                    // 声卡名称
	Ports map[string]*PortConfig    // 端口配置映射 (端口名称 => 端口配置)
}

// MuteConfig 静音配置结构体
// 存储全局静音配置
type MuteConfig struct {
	MuteOutput bool // 输出静音
	MuteInput  bool // 输入静音
}

// ConfigKeeper 配置管理器
// 管理音频设备的配置信息，包括声卡、端口和静音配置
type ConfigKeeper struct {
	Cards    map[string]*CardConfig // 声卡配置映射 (声卡名称 => 声卡配置)
	Mute     *MuteConfig            // 全局静音配置
	file     string                 // 配置文件路径
	muteFile string                 // 静音配置文件路径
	mu       sync.Mutex             // 互斥锁
}

// createConfigKeeperSingleton 创建配置管理器单例工厂函数
// path: 配置文件路径
// mutePath: 静音配置文件路径
func createConfigKeeperSingleton(path string, mutePath string) func() *ConfigKeeper {
	var ck *ConfigKeeper = nil
	return func() *ConfigKeeper {
		if ck == nil {
			ck = NewConfigKeeper(path, mutePath)
		}
		return ck
	}
}

// 获取配置管理器单例
// 由于配置管理需要在很多个对象中使用，放在Audio对象中需要添加额外参数传递到各个模块很不方便，因此在此创建一个全局的单例
var globalConfigKeeperFile = filepath.Join(basedir.GetUserConfigDir(), "deepin/dde-daemon/audio-config-keeper.json")
var globalConfigKeeperMuteFile = filepath.Join(basedir.GetUserConfigDir(), "deepin/dde-daemon/audio-config-keeper-mute.json")
var GetConfigKeeper = createConfigKeeperSingleton(globalConfigKeeperFile, globalConfigKeeperMuteFile)

// NewConfigKeeper 创建新的配置管理器实例
// path: 配置文件路径
// mutePath: 静音配置文件路径
func NewConfigKeeper(path string, mutePath string) *ConfigKeeper {
	return &ConfigKeeper{
		Cards:    make(map[string]*CardConfig),
		Mute:     NewMuteConfig(),
		file:     path,
		muteFile: mutePath,
	}
}

// NewMuteConfig 创建新的静音配置实例
func NewMuteConfig() *MuteConfig {
	return &MuteConfig{
		MuteOutput: false,
		MuteInput:  false,
	}
}

// NewCardConfig 创建新的声卡配置实例
// name: 声卡名称
func NewCardConfig(name string) *CardConfig {
	return &CardConfig{
		Name:  name,
		Ports: make(map[string]*PortConfig),
	}
}

// NewPortConfig 创建新的端口配置实例
// name: 端口名称
func NewPortConfig(name string) *PortConfig {
	pname := strings.ToLower(name)
	volume := 0.5
	if strings.Contains(pname, "input") {
		volume = defaultInputVolume
		logger.Info("NewPortConfig set defaultInputVolume : ", volume)
	} else if strings.Contains(pname, "output") {
		if strings.Contains(pname, "headphone") || strings.Contains(pname, "headset") {
			volume = defaultHeadphoneOutputVolume
			logger.Info("NewPortConfig set defaultHeadphoneOutputVolume : ", volume)
		} else {
			volume = defaultOutputVolume
			logger.Info("NewPortConfig set defaultOutputVolume : ", volume)
		}

	}
	return &PortConfig{
		Name:           name,
		Enabled:        true,
		Volume:         volume,
		IncreaseVolume: false,
		Balance:        0.0,
		ReduceNoise:    defaultReduceNoise,
		Mute:           false,
	}
}

// Save 保存配置到文件
// 将当前配置保存到JSON文件
func (ck *ConfigKeeper) Save() error {
	data, err := json.MarshalIndent(ck.Cards, "", "  ")
	if err != nil {
		logger.Warning(err)
		return err
	}

	err = ioutil.WriteFile(ck.file, data, 0644)
	if err != nil {
		logger.Warning(err)
		// 这里不返回，因为可能可以写另一个配置
	}

	data, err = json.MarshalIndent(ck.Mute, "", "  ")
	if err != nil {
		logger.Warning(err)
		return err
	}

	err = ioutil.WriteFile(ck.muteFile, data, 0644)
	if err != nil {
		logger.Warning(err)
		return err
	}

	return nil
}

// Load 从文件加载配置
// 从JSON文件加载配置信息
func (ck *ConfigKeeper) Load() error {
	data, err := ioutil.ReadFile(ck.file)
	if err != nil {
		logger.Warning(err)
		return err
	}

	err = json.Unmarshal(data, &ck.Cards)
	if err != nil {
		logger.Warning(err)
	}

	data, err = ioutil.ReadFile(ck.muteFile)
	if err != nil {
		logger.Warning(err)
		return err
	}

	err = json.Unmarshal(data, &ck.Mute)
	if err != nil {
		logger.Warning(err)
		return err
	}

	return nil
}

// Print 打印配置信息
// 将当前配置以JSON格式输出到日志
func (ck *ConfigKeeper) Print() {
	data, err := json.MarshalIndent(ck.Cards, "", "  ")
	if err != nil {
		logger.Warning(err)
		return
	}
	logger.Debug(string(data))
}

// UpdateCardConfig 更新声卡配置
// cardConfig: 声卡配置对象
func (ck *ConfigKeeper) UpdateCardConfig(cardConfig *CardConfig) {
	ck.Cards[cardConfig.Name] = cardConfig
}

// RemoveCardConfig 移除声卡配置
// cardName: 声卡名称
func (ck *ConfigKeeper) RemoveCardConfig(cardName string) {
	delete(ck.Cards, cardName)
}

// GetCardAndPortConfig 获取声卡和端口配置
// cardName: 声卡名称
// portName: 端口名称
// 如果配置不存在则创建默认配置
func (ck *ConfigKeeper) GetCardAndPortConfig(cardName string, portName string) (*CardConfig, *PortConfig) {
	card, ok := ck.Cards[cardName]
	if !ok {
		card = NewCardConfig(cardName)
		port := NewPortConfig(portName)
		card.UpdatePortConfig(port)
		ck.UpdateCardConfig(card)
		return card, port
	}

	port, ok := card.Ports[portName]
	if !ok {
		port = NewPortConfig(portName)
		card.UpdatePortConfig(port)
		ck.UpdateCardConfig(card)
	}
	return card, port
}

// SetEnabled 设置端口启用状态
// cardName: 声卡名称
// portName: 端口名称
// enabled: 是否启用
func (ck *ConfigKeeper) SetEnabled(cardName string, portName string, enabled bool) {
	ck.mu.Lock()
	defer ck.mu.Unlock()

	_, port := ck.GetCardAndPortConfig(cardName, portName)
	port.Enabled = enabled
	ck.Save()
}

// SetVolume 设置端口音量
// cardName: 声卡名称
// portName: 端口名称
// volume: 音量值
func (ck *ConfigKeeper) SetVolume(cardName string, portName string, volume float64) {
	ck.mu.Lock()
	defer ck.mu.Unlock()

	_, port := ck.GetCardAndPortConfig(cardName, portName)
	port.Volume = volume
	ck.Save()
}

// SetIncreaseVolume 设置端口音量增强
// cardName: 声卡名称
// portName: 端口名称
// enhance: 是否启用音量增强
func (ck *ConfigKeeper) SetIncreaseVolume(cardName string, portName string, enhance bool) {
	ck.mu.Lock()
	defer ck.mu.Unlock()

	_, port := ck.GetCardAndPortConfig(cardName, portName)
	port.IncreaseVolume = enhance
	ck.Save()
}

// SetBalance 设置端口声道平衡
// cardName: 声卡名称
// portName: 端口名称
// balance: 声道平衡值
func (ck *ConfigKeeper) SetBalance(cardName string, portName string, balance float64) {
	ck.mu.Lock()
	defer ck.mu.Unlock()

	_, port := ck.GetCardAndPortConfig(cardName, portName)
	port.Balance = balance
	ck.Save()
}

// SetReduceNoise 设置端口降噪
// cardName: 声卡名称
// portName: 端口名称
// reduce: 是否启用降噪
func (ck *ConfigKeeper) SetReduceNoise(cardName string, portName string, reduce bool) {
	ck.mu.Lock()
	defer ck.mu.Unlock()

	_, port := ck.GetCardAndPortConfig(cardName, portName)
	port.ReduceNoise = reduce
	ck.Save()
}

// SetMute 设置端口静音
// cardName: 声卡名称
// portName: 端口名称
// mute: 是否静音
func (ck *ConfigKeeper) SetMute(cardName string, portName string, mute bool) {
	ck.mu.Lock()
	defer ck.mu.Unlock()

	_, port := ck.GetCardAndPortConfig(cardName, portName)
	port.Mute = mute
	ck.Save()
}

// SetMuteOutput 设置全局输出静音
// mute: 是否静音
func (ck *ConfigKeeper) SetMuteOutput(mute bool) {
	ck.mu.Lock()
	defer ck.mu.Unlock()

	ck.Mute.MuteOutput = mute
	ck.Save()
}

// SetMuteInput 设置全局输入静音
// mute: 是否静音
func (ck *ConfigKeeper) SetMuteInput(mute bool) {
	ck.mu.Lock()
	defer ck.mu.Unlock()

	ck.Mute.MuteInput = mute
	ck.Save()
}

// SetMuteAll 设置所有端口静音
// mute: 是否静音
func (ck *ConfigKeeper) SetMuteAll(mute bool) {
	ck.mu.Lock()
	defer ck.mu.Unlock()

	for _, card := range ck.Cards {
		for _, port := range card.Ports {
			port.Mute = mute
		}
	}
	ck.Save()
}

func (card *CardConfig) UpdatePortConfig(portConfig *PortConfig) {
	card.Ports[portConfig.Name] = portConfig
}

func (card *CardConfig) RemovePortConfig(portName string) {
	delete(card.Ports, portName)
}
