package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"time"

	"golang.org/x/crypto/ssh"
	//	"github.com/mitchellh/go-homedir"
	//	"github.com/davecgh/go-spew/spew"
)

func publicKeyAuthFunc(kPath string) ssh.AuthMethod {
	// keyPath, err := homedir.Expand(kPath)
	// if err != nil {
	// 		log.Fatal("find key's home dir failed", err)
	// }
	// key, err := ioutil.ReadFile(keyPath )
	key, err := ioutil.ReadFile(kPath )
	if err != nil {
			log.Fatal("ssh key file read failed", err)
	}
	// Create the Signer for this private key.
	signer, err := ssh.ParsePrivateKey(key)
	if err != nil {
			log.Fatal("ssh key signer failed", err)
	}
	return ssh.PublicKeys(signer)
}
func runSSH(cfg SSHAccess, cmds ...string ) ([]byte, error) {
	// fmt.Fprintf(os.Stderr, "SSH: %#v\n", cfg)
	fmt.Fprintf(os.Stderr, "%s - running : %s\n\n", cfg.Host, cmds)

	// Create SSHP login configuration
	config := &ssh.ClientConfig{
			Timeout: time.Second, //ssh connection time out time is one second, if SSH validation error returns in one second
			User:    cfg.User,
			HostKeyCallback: ssh.InsecureIgnoreHostKey(), // This is OK, but not safe enough.
			// HostKeyCallback: hostKeyCallBackFunc(h.Host),
	}
	if cfg.UType == "password" {
			config.Auth = []ssh.AuthMethod{ssh.Password(cfg.Password)}
	} else {
			config.Auth = []ssh.AuthMethod{publicKeyAuthFunc(cfg.KeyPath)}
	}
	addr := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
	conn, err := ssh.Dial("tcp", addr,config)
	if err != nil {
		log.Fatal("Failed to dial SSH client", err)
		return []byte{}, err
	}
	session, err := conn.NewSession()
	if err != nil {
		log.Fatal(err)
	}
	defer session.Close()
	modes := ssh.TerminalModes{
		ssh.ECHO:          0,     // disable echoing
		ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
		ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
	}
	err = session.RequestPty("xterm", 80, 40, modes)
	if err != nil {
		return []byte{}, err
	}
	in, err := session.StdinPipe()
	if err != nil {
		log.Fatal(err)
	}
	out, err := session.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	var output []byte
	go func(in io.WriteCloser, out io.Reader, output *[]byte) {
		var (
			line string
			r    = bufio.NewReader(out)
		)
		for {
			b, err := r.ReadByte()
			if err != nil {
				break
			}
			*output = append(*output, b)
			if b == byte('\n') {
				line = ""
				continue
			}
			line += string(b)
			if strings.HasPrefix(line, "[sudo] password for ") && strings.HasSuffix(line, ": ") {
				_, err = in.Write([]byte(cfg.Password+ "\n"))
				if err != nil {
					break
				}
			}
		}
	}(in, out, &output)
	cmd := strings.Join(cmds, "; ")
	_, err = session.Output(cmd)
	if err != nil {
		return []byte{}, err
	}
	return output, nil
}