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

package main

import (
	"bufio"
	"bytes"
	"compress/gzip"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"github.com/godbus/dbus/v5"
	"github.com/linuxdeepin/go-lib/keyfile"
)

func getLightDMAutoLoginUser() (string, error) {
	kf := keyfile.NewKeyFile()
	err := kf.LoadFromFile("/etc/lightdm/lightdm.conf")
	if err != nil {
		return "", err
	}

	v, err := kf.GetString("Seat:*", "autologin-user")
	return v, err
}

func getAsoundStateFile(uid int) string {
	return filepath.Join(homeDir, fmt.Sprintf("asound-state-%d.gz", uid))
}

func runAlsaCtlStore(uid int) error {
	stateFilename := getAsoundStateFile(uid)
	logger.Debug("store ALSA state to file:", stateFilename)
	fh, err := os.Create(stateFilename)
	if err != nil {
		return err
	}
	defer func() {
		_ = fh.Close()
	}()

	bufWriter := bufio.NewWriter(fh)
	gzipWriter := gzip.NewWriter(bufWriter)

	cmd := exec.Command(alsaCtlBin, "-f", "-", "store")
	cmd.Stdout = gzipWriter
	var errBuf bytes.Buffer
	cmd.Stderr = &errBuf
	err = cmd.Run()
	if err != nil {
		logger.Warningf("alsactl std err: %s", errBuf.String())
		return err
	}

	err = gzipWriter.Close()
	if err != nil {
		return err
	}

	err = bufWriter.Flush()
	if err != nil {
		return err
	}

	return nil
}

func runALSARestore(uid int) error {
	stateFilename := getAsoundStateFile(uid)
	logger.Debug("restore ALSA state from file:", stateFilename)
	fh, err := os.Open(stateFilename)
	if err != nil {
		return err
	}
	bufReader := bufio.NewReader(fh)
	gzipReader, err := gzip.NewReader(bufReader)
	if err != nil {
		return err
	}
	content, err := ioutil.ReadAll(gzipReader)
	if err != nil {
		return err
	}
	err = gzipReader.Close()
	if err != nil {
		return err
	}

	var errBuf bytes.Buffer
	contentReader := bytes.NewReader(content)
	for i := 0; i < 6; i++ {
		cmd := exec.Command(alsaCtlBin, "-f", "-", "restore")
		if i != 0 {
			_, _ = contentReader.Seek(0, io.SeekStart)
			errBuf.Reset()
			logger.Warning("retry restore alsa state", i)
		}
		cmd.Stdin = contentReader
		cmd.Stderr = &errBuf
		err = cmd.Run()

		if exitErr, ok := err.(*exec.ExitError); ok {
			if exitErr.ExitCode() == 99 {
				// 99 是 alsactl 的 init 过程的报错，可以忽略。
				err = nil
			}
		}

		if err != nil {
			time.Sleep(500 * time.Millisecond)
		} else {
			break
		}
	}
	if err != nil {
		logger.Warningf("alsactl std err: %s", errBuf.Bytes())
		return err
	}
	return nil
}

func getLastUser() (int, error) {
	sysBus, err := dbus.SystemBus()
	if err != nil {
		return -1, err
	}
	lockServiceObj := sysBus.Object("org.deepin.dde.LockService1",
		"/org/deepin/dde/LockService1")
	var userJson string
	err = lockServiceObj.Call("org.deepin.dde.LockService1.CurrentUser", 0).Store(&userJson)
	if err != nil {
		return -1, err
	}

	var v struct {
		Uid int
	}
	err = json.Unmarshal([]byte(userJson), &v)
	if err != nil {
		return -1, err
	}
	return v.Uid, nil
}
