﻿package ssh

import (
	"fmt"
	"net"
	"strconv"
	"strings"

	"golang.org/x/crypto/ssh"
)

func NewClient(conn net.Conn, host string, port int, username string) (*ssh.Client, error) {
	authentications := make([]ssh.AuthMethod, 0)
	return newClientWithAuthMethods(conn, host, port, username, authentications)
}

func NewClientWithPassword(conn net.Conn, host string, port int, username string, password string) (*ssh.Client, error) {
	authentications := make([]ssh.AuthMethod, 0)
	authentications = append(authentications, ssh.Password(password))
	authentications = append(authentications, ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) ([]string, error) {
		if len(questions) == 1 {
			return []string{password}, nil
		}
		return nil, fmt.Errorf("unexpected keyboard interactive question [%s]", strings.Join(questions, ", "))
	}))
	return newClientWithAuthMethods(conn, host, port, username, authentications)
}

func NewClientWithKey(conn net.Conn, host string, port int, username string, key, keyPassphrase string) (*ssh.Client, error) {
	var signer ssh.Signer
	var err error
	if keyPassphrase != "" {
		signer, err = ssh.ParsePrivateKeyWithPassphrase([]byte(key), []byte(keyPassphrase))
	} else {
		signer, err = ssh.ParsePrivateKey([]byte(key))
	}
	if err != nil {
		return nil, err
	}

	authentications := make([]ssh.AuthMethod, 0)
	authentications = append(authentications, ssh.PublicKeys(signer))
	return newClientWithAuthMethods(conn, host, port, username, authentications)
}

func newClientWithAuthMethods(conn net.Conn, host string, port int, username string, authMethods []ssh.AuthMethod) (*ssh.Client, error) {
	addr := net.JoinHostPort(host, strconv.Itoa(int(port)))

	sshConn, chans, reqs, err := ssh.NewClientConn(conn, addr, &ssh.ClientConfig{
		User:            username,
		Auth:            authMethods,
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	})
	if err != nil {
		return nil, err
	}

	return ssh.NewClient(sshConn, chans, reqs), nil
}
