package main

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"strings"
)

// runGuided is what happens when somebody double-clicks the program instead of
// typing its name at a prompt.
//
// Without this, Explorer opens a console, main() finds no arguments, prints
// the usage text to stderr and exits — and Windows destroys the window in the
// same instant. From the other side of the screen that is indistinguishable
// from a crash. So when we know we were double-clicked, we ask the one
// question the program actually needs and stay on screen until the reader is
// done.
//
// This path is entered ONLY when there are no arguments and both ends of the
// program are a real console. Any scripted or piped use takes exactly the same
// code path it always did.
func runGuided() {
	in := bufio.NewScanner(os.Stdin)

	fmt.Println()
	fmt.Println("  SSHDesk")
	fmt.Println("  Read your SSH config the way SSH reads it.")
	fmt.Println()
	fmt.Println("  Your config file is a stack of rules where the first match wins and")
	fmt.Println("  a wildcard near the top can quietly override everything below it.")
	fmt.Println("  I list the machines it describes, then point out the mistakes: rules")
	fmt.Println("  that never take effect, keys that are missing or readable by anyone,")
	fmt.Println("  jump hosts that loop, and settings that weaken your security.")
	fmt.Println()
	fmt.Println("  It only reads. Your config is never modified, and no connection is")
	fmt.Println("  ever made.")
	fmt.Println()

	suggested := suggestedConfig()
	var path string
	for {
		fmt.Println("  Which config file shall I read?")
		if suggested != "" {
			fmt.Printf("  (press Enter for %s)\n", suggested)
		} else {
			fmt.Println("  (it is usually called \"config\", in the .ssh folder in your home folder)")
		}
		fmt.Print("  > ")

		if !in.Scan() {
			// stdin closed on us; there is nothing sensible left to ask.
			return
		}
		answer := strings.TrimSpace(in.Text())
		answer = strings.Trim(answer, `"`)
		if answer == "" {
			answer = suggested
		}
		if answer == "" {
			fmt.Println()
			fmt.Println("  I need a config file to read. Try again, or close this window.")
			fmt.Println()
			continue
		}

		info, err := os.Stat(answer)
		if err != nil {
			fmt.Println()
			fmt.Printf("  I cannot find %q.\n", answer)
			fmt.Println("  Tip: you can drag the file — or the folder holding it — from")
			fmt.Println("  Explorer onto this window to paste its location, then press Enter.")
			fmt.Println()
			continue
		}
		if info.IsDir() {
			// Dragging the .ssh folder instead of the file inside it is an
			// easy mistake to make and an easy one to just fix for them.
			inside := filepath.Join(answer, "config")
			if fi, err := os.Stat(inside); err == nil && !fi.IsDir() {
				fmt.Println()
				fmt.Printf("  That is a folder, so I will read %s inside it.\n", inside)
				path = inside
				break
			}
			fmt.Println()
			fmt.Printf("  %q is a folder, and there is no file called \"config\" in it.\n", answer)
			fmt.Println("  Give me the config file itself.")
			fmt.Println()
			continue
		}
		path = answer
		break
	}

	fmt.Println()
	cmdHosts([]string{"--config", path})
	fmt.Println()
	cmdCheck([]string{"--config", path})

	fmt.Println()
	fmt.Println("  Done. Your config was not modified.")
	fmt.Println("  There is a command-line version too, which can also explain a single")
	fmt.Println("  host or draw your jump-host map: sshdesk --help")
	pause(in)
}

// suggestedConfig offers the file SSH itself would read, but only when it is
// really there — pressing Enter must never open with an error.
func suggestedConfig() string {
	home, err := os.UserHomeDir()
	if err != nil {
		return ""
	}
	candidate := filepath.Join(home, ".ssh", "config")
	if info, err := os.Stat(candidate); err == nil && !info.IsDir() {
		return candidate
	}
	return ""
}

// pause keeps the console window open. Explorer closes it the moment the
// process exits, so without this the reader never sees the output.
func pause(in *bufio.Scanner) {
	fmt.Println()
	fmt.Print("  Press Enter to close this window. ")
	in.Scan()
}
