package icsutil

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/signal"
	"strings"
	"syscall"

	"gitlab.com/cinnamon/voiceagent/icsconf"
	"gitlab.com/cinnamon/voiceagent/icserror"
)

const PNAME = "voiceagent"

func Deamonize() (int, error) {
	pid, _, sysErr := syscall.RawSyscall(syscall.SYS_FORK, 0, 0, 0)
	if sysErr != 0 {
		fmt.Println("fail to call fork")
		return -1, fmt.Errorf("fail to call fork - %d", sysErr)
	}
	if pid > 0 { //parent
		//return int(pid), nil
		fmt.Printf("Child Process Created %d\n", int(pid))
		os.Exit(0)
	} else if int(pid) < 0 {
		//fmt.Println("child id is incorrect")
		return int(pid), fmt.Errorf("child id is incorrect")
	} /* else if int(pid) == 0 { //child
		p := os.Getpid()
		fmt.Printf("Child Process PID %d\n", p)
	}*/

	ret, err := syscall.Setsid()
	if err != nil || ret < 0 {
		//fmt.Println("fail to call setsid", pid, err)
		return int(pid), fmt.Errorf("Fail to call setsid")
	}

	signal.Ignore(syscall.SIGHUP)
	syscall.Umask(0)

	conf := icsconf.GetIcsConfig()
	homeDir := conf.GetHomeDir()
	cmdline := fmt.Sprintf("%s/bin/%s", homeDir, PNAME)
	attr := &os.ProcAttr{Env: os.Environ()}
	p, perr := os.StartProcess(cmdline, []string{""}, attr)
	if perr != nil {
		return -1, perr
	}

	if werr := WritePID(p.Pid); werr != nil {
		fmt.Println("Error Write PID :", werr)
	}

	return p.Pid, nil
}

func CloseSTDIO() {
	for iter := 0; iter < 3; iter++ {
		syscall.Close(iter)
	}
}

func WritePID(pid int) *icserror.IcsError {
	isStop := false
	var homeDir string
	for _, e := range os.Environ() {
		s := strings.SplitN(e, "=", 2)
		if strings.Compare(s[0], "ICSVA_ROOT") == 0 {
			homeDir = s[1]
			//service.SetHomeDir(s[1])
			isStop = true
			break
		}
	}

	if isStop {
		pidFilename := fmt.Sprintf("%s/icsva.pid", homeDir)
		spid := fmt.Sprintf("%d", pid)
		ioutil.WriteFile(pidFilename, []byte(spid), 0666)
	} else {
		return icserror.ICSERRNotFoundHome
	}

	return nil
}

func CheckPID() bool {
	isStop := false
	var homeDir string
	for _, e := range os.Environ() {
		s := strings.SplitN(e, "=", 2)
		if strings.Compare(s[0], "ICSVA_ROOT") == 0 {
			homeDir = s[1]
			//service.SetHomeDir(s[1])
			isStop = true
			break
		}
	}

	if isStop {
		pidFilename := fmt.Sprintf("%s/icsva.pid", homeDir)
		fd, err := os.Open(pidFilename)
		if err != nil {
			fd.Close()
			return false
		}
		pid := make([]byte, 12)
		rlen, rerr := fd.Read(pid)
		if rerr != nil {
			return false
		}
		fd.Close()

		cmdline := fmt.Sprintf("/proc/%s/exe", string(pid[:rlen]))
		//cmdline := fmt.Sprintf("/proc/%s/cmdline", string(pid[:rlen]))
		/*
			cfd, cerr := os.Open(cmdline)
			if cerr != nil {
				cfd.Close()
				return false
			}
			pname := make([]byte, 128)
			rlen, rerr = cfd.Read(pname)
			if rerr != nil {
				return false
			}
			cfd.Close()
		*/
		pname, rlerr := os.Readlink(cmdline)
		if rlerr != nil {
			return false
		}

		fmt.Println(pname)

		if strings.Contains(pname, PNAME) {
			return true
		}
	}

	return false
}

// Process Check
const PNAMEC = "voiceagentCheck"

func DeamonizeProcessCheck() (int, error) {
	pid, _, sysErr := syscall.RawSyscall(syscall.SYS_FORK, 0, 0, 0)
	if sysErr != 0 {
		//fmt.Println("fail to call fork")
		return -1, fmt.Errorf("fail to call fork - %d", sysErr)
	}
	if pid > 0 { //parent
		//return int(pid), nil
		//fmt.Printf("Child Process Created %d\n", int(pid))
		os.Exit(0)
	} else if int(pid) < 0 {
		//fmt.Println("child id is incorrect")
		return int(pid), fmt.Errorf("child id is incorrect")
	} /* else if int(pid) == 0 { //child
		p := os.Getpid()
		fmt.Printf("Child Process PID %d\n", p)
	}*/

	ret, err := syscall.Setsid()
	if err != nil || ret < 0 {
		//fmt.Println("fail to call setsid", pid, err)
		return int(pid), fmt.Errorf("Fail to call setsid")
	}

	signal.Ignore(syscall.SIGHUP)
	syscall.Umask(0)

	conf := icsconf.GetIcsConfig()
	homeDir := conf.GetHomeDir()
	cmdline := fmt.Sprintf("%s/bin/%s", homeDir, PNAMEC)
	attr := &os.ProcAttr{Env: os.Environ()}
	p, perr := os.StartProcess(cmdline, []string{""}, attr)
	if perr != nil {
		return -1, perr
	}

	return p.Pid, nil
}

func PWritePID(pid int) *icserror.IcsError {
	isStop := false
	var homeDir string
	for _, e := range os.Environ() {
		s := strings.SplitN(e, "=", 2)
		if strings.Compare(s[0], "ICSVA_ROOT") == 0 {
			homeDir = s[1]
			//service.SetHomeDir(s[1])
			isStop = true
			break
		}
	}

	if isStop {
		pidFilename := fmt.Sprintf("%s/icsvap.pid", homeDir)
		spid := fmt.Sprintf("%d", pid)
		ioutil.WriteFile(pidFilename, []byte(spid), 0666)
	} else {
		return icserror.ICSERRNotFoundHome
	}

	return nil
}

func PCheckPID() bool {
	isStop := false
	var homeDir string
	for _, e := range os.Environ() {
		s := strings.SplitN(e, "=", 2)
		if strings.Compare(s[0], "ICSVA_ROOT") == 0 {
			homeDir = s[1]
			//service.SetHomeDir(s[1])
			isStop = true
			break
		}
	}

	if isStop {
		pidFilename := fmt.Sprintf("%s/icsvap.pid", homeDir)
		fd, err := os.Open(pidFilename)
		if err != nil {
			fd.Close()
			return false
		}
		pid := make([]byte, 12)
		rlen, rerr := fd.Read(pid)
		if rerr != nil {
			return false
		}
		fd.Close()

		cmdline := fmt.Sprintf("/proc/%s/exe", string(pid[:rlen]))
		//cmdline := fmt.Sprintf("/proc/%s/cmdline", string(pid[:rlen]))
		/*
			cfd, cerr := os.Open(cmdline)
			if cerr != nil {
				cfd.Close()
				return false
			}
			pname := make([]byte, 128)
			rlen, rerr = cfd.Read(pname)
			if rerr != nil {
				return false
			}
			cfd.Close()
		*/
		pname, rlerr := os.Readlink(cmdline)
		if rlerr != nil {
			return false
		}

		fmt.Println(pname)

		if strings.Contains(pname, PNAMEC) {
			return true
		}
	}

	return false
}