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

package audio

import (
	"bufio"
	"bytes"
	"encoding/json"
	"io/ioutil"
	"math"
	"strings"
	"unicode"

	dbus "github.com/godbus/dbus"
	"github.com/linuxdeepin/dde-api/soundutils"
	ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus"
	mpris2 "github.com/linuxdeepin/go-dbus-factory/org.mpris.mediaplayer2"
	//"github.com/linuxdeepin/go-lib/pulse"
)

// isVolumeValid 检查音量值是否有效
// v: 音量值
// 返回音量是否在有效范围内 (0 到 gMaxUIVolume)
func isVolumeValid(v float64) bool {
	if v < 0 || v > gMaxUIVolume {
		return false
	}
	return true
}

// playFeedback 播放音量反馈音效
// 使用默认设备播放系统音效
func playFeedback() {
	playFeedbackWithDevice("")
}

// playFeedbackWithDevice 使用指定设备播放音量反馈音效
// device: 设备名称，为空时使用默认设备
func playFeedbackWithDevice(device string) {
	go func() {
		err := soundutils.PlaySystemSound(soundutils.EventAudioVolumeChanged, device)
		if err != nil {
			logger.Warning(err)
		}
	}()
}

// toJSON 将对象转换为JSON字符串
// v: 要转换的对象
// 返回JSON字符串，转换失败时返回空字符串
func toJSON(v interface{}) string {
	data, err := json.Marshal(v)
	if err != nil {
		return ""
	}
	return string(data)
}

const (
	mprisPlayerDestPrefix = "org.mpris.MediaPlayer2" // MPRIS播放器DBus名称前缀
)

// getMprisPlayers 获取所有MPRIS播放器列表
// sessionConn: 会话DBus连接
// 返回播放器名称列表和错误信息
func getMprisPlayers(sessionConn *dbus.Conn) ([]string, error) {
	var playerNames []string
	dbusDaemon := ofdbus.NewDBus(sessionConn)
	names, err := dbusDaemon.ListNames(0)
	if err != nil {
		return nil, err
	}
	for _, name := range names {
		if strings.HasPrefix(name, mprisPlayerDestPrefix) {
			// is mpris player
			playerNames = append(playerNames, name)
		}
	}
	return playerNames, nil
}

// pauseAllPlayers 暂停所有MPRIS播放器
// 用于耳机拔出时自动暂停所有媒体播放
func pauseAllPlayers() {
	sessionConn, err := dbus.SessionBus()
	if err != nil {
		return
	}
	playerNames, err := getMprisPlayers(sessionConn)
	if err != nil {
		logger.Warning("getMprisPlayers failed:", err)
		return
	}

	logger.Debug("pause all players")
	for _, playerName := range playerNames {
		player := mpris2.NewMediaPlayer(sessionConn, playerName)
		err := player.Player().Pause(0)
		if err != nil {
			logger.Warningf("failed to pause player %s: %v", playerName, err)
		}
	}
}

// floatPrecision 四舍五入到指定精度
// f: 浮点数
// 返回精确到小数点后2位的浮点数
func floatPrecision(f float64) float64 {
	// 精确到小数点后2位
	pow10N := math.Pow10(2)
	return math.Trunc((f+0.5/pow10N)*pow10N) / pow10N
	// return math.Trunc((f)*pow10N) / pow10N
}

const defaultPaFile = "/etc/pulse/default.pa" // 默认脉冲音频配置文件路径

// loadDefaultPaConfig 加载默认脉冲音频配置
// filename: 配置文件路径
// 返回解析后的配置信息
func loadDefaultPaConfig(filename string) (cfg defaultPaConfig) {
	content, err := ioutil.ReadFile(filename)
	if err != nil {
		logger.Warning(err)
		return
	}

	scanner := bufio.NewScanner(bytes.NewReader(content))
	for scanner.Scan() {
		line := scanner.Bytes()
		line = bytes.TrimLeftFunc(line, unicode.IsSpace)
		if bytes.HasPrefix(line, []byte{'#'}) {
			continue
		}

		if bytes.Contains(line, []byte("set-default-sink")) {
			cfg.setDefaultSink = true
		}
		if bytes.Contains(line, []byte("set-default-source")) {
			cfg.setDefaultSource = true
		}
	}
	err = scanner.Err()
	if err != nil {
		logger.Warning(err)
	}
	return
}

// defaultPaConfig 默认脉冲音频配置结构体
// 存储从配置文件中解析的默认设置
type defaultPaConfig struct {
	setDefaultSource bool // 是否设置默认输入设备
	setDefaultSink   bool // 是否设置默认输出设备
}
