package stdio

import (
	"bufio"
	"fmt"
	"io"
	"strings"
)

// noninteractiveStdio interacts with stdin/stdout/stderr as files, with no user interaction.
type noninteractiveStdio struct {
	in  *bufio.Scanner
	out io.Writer
	err io.Writer
}

func (t *noninteractiveStdio) Write(p []byte) (int, error) {
	return t.out.Write(p)
}

func (t *noninteractiveStdio) WriteErr(p []byte) (int, error) {
	return t.err.Write(p)
}

func (t *noninteractiveStdio) Banner(message string) error {
	_, err := fmt.Fprintf(t.out, "> %s\n", message)
	return err
}

func (t *noninteractiveStdio) Error(message string) error {
	_, err := fmt.Fprintf(t.err, "X %s\n", message)
	return err
}

func (t *noninteractiveStdio) IsInteractive() bool {
	return false
}

func (t *noninteractiveStdio) GetStringInput(prompt, defaultValue string) (string, error) {
	if inLine := t.readStdinLine(); inLine != "" {
		return inLine, nil
	}
	if defaultValue != "" {
		return defaultValue, nil
	}
	return "", fmt.Errorf("couldn't get input for prompt %q: no data on stdin", prompt)
}

func (t *noninteractiveStdio) GetSecret(prompt string, minLen int) (string, error) {
	inLine := t.readStdinLine()
	if len(inLine) >= minLen {
		return inLine, nil
	} else if minLen > 0 {
		return "", fmt.Errorf("value for prompt %q is too short: min length is %d", prompt, minLen)
	}
	return "", nil
}

func (t *noninteractiveStdio) GetPassword(prompt string) (string, error) {
	return t.GetSecret(prompt, MinPasswordLen)
}

func (t *noninteractiveStdio) GetConfirm(prompt string) (answer bool) {
	return strings.HasPrefix(t.readStdinLine(), "y")
}

// readStdinLine returns the first line of text on stdin, or empty string if stdin is at EOF.
func (t *noninteractiveStdio) readStdinLine() string {
	if !t.in.Scan() {
		return ""
	}
	return t.in.Text()
}
