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

package audio

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

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

var (
	fileLocker  sync.Mutex // 文件操作锁
	configCache *config   // 配置缓存
	configFile  = filepath.Join(basedir.GetUserConfigDir(), "deepin/dde-daemon/audio.json") // 配置文件路径
)

// config 音频配置结构体
// 存储音频系统的配置信息
type config struct {
	Profiles   map[string]string // 配置文件映射 (声卡名称 => 活动配置文件)
	Sink       string            // 默认输出设备
	Source     string            // 默认输入设备
	SinkPort   string            // 默认输出端口
	SourcePort string            // 默认输入端口

	SinkVolume   float64 // 输出设备音量
	SourceVolume float64 // 输入设备音量
}

// string 将配置转换为JSON字符串
// 用于调试和日志输出
func (c *config) string() string {
	data, _ := json.Marshal(c)
	return string(data)
}

// equal 比较两个配置是否相等
// b: 要比较的配置
// 返回是否相等
func (c *config) equal(b *config) bool {
	if c == nil && b == nil {
		return true
	}
	if c == nil || b == nil {
		return false
	}
	return c.Sink == b.Sink &&
		c.Source == b.Source &&
		c.SinkPort == b.SinkPort &&
		c.SourcePort == b.SourcePort &&
		c.SinkVolume == b.SinkVolume &&
		c.SourceVolume == b.SourceVolume &&
		mapStrStrEqual(c.Profiles, b.Profiles)
}

// readConfig 读取配置文件
// 从JSON文件加载配置信息，支持缓存机制
// 返回配置对象和错误信息
func readConfig() (*config, error) {
	fileLocker.Lock()
	defer fileLocker.Unlock()

	if configCache != nil {
		return configCache, nil
	}

	var info config
	content, err := ioutil.ReadFile(configFile)
	if err != nil {
		return nil, err
	}
	err = json.Unmarshal(content, &info)
	if err != nil {
		return nil, err
	}

	configCache = &info
	return configCache, nil
}

// saveConfig 保存配置文件
// info: 要保存的配置对象
// 将配置保存到JSON文件，支持缓存机制
func saveConfig(info *config) error {
	fileLocker.Lock()
	defer fileLocker.Unlock()

	if configCache.equal(info) {
		logger.Debug("[saveConfigInfo] config info not changed")
		return nil
	} else {
		logger.Debug("[saveConfigInfo] will save:", info.string())
	}

	content, err := json.Marshal(info)
	if err != nil {
		return err
	}
	err = os.MkdirAll(filepath.Dir(configFile), 0755)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(configFile, content, 0644)
	if err != nil {
		return err
	}

	configCache = info
	return nil
}

// removeConfig 移除配置文件
// 删除所有音频相关的配置文件，用于重置配置
func removeConfig() {
	fileLocker.Lock()
	defer fileLocker.Unlock()

	err := os.Remove(configFile)
	if err != nil && !os.IsNotExist(err) {
		logger.Warning(err)
	}

	err = os.Remove(globalConfigKeeperFile)
	if err != nil && !os.IsNotExist(err) {
		logger.Warning(err)
	}

	err = os.Remove(globalPrioritiesFilePath)
	if err != nil && !os.IsNotExist(err) {
		logger.Warning(err)
	}

	err = os.Remove(bluezAudioConfigFilePath)
	if err != nil && !os.IsNotExist(err) {
		logger.Warning(err)
	}
}

// mapStrStrEqual 比较两个字符串映射是否相等
// a, b: 要比较的字符串映射
// 返回是否相等
func mapStrStrEqual(a, b map[string]string) bool {
	if len(a) != len(b) {
		return false
	}

	for k, v := range a {
		if w, ok := b[k]; !ok || v != w {
			return false
		}
	}
	return true
}
