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 thing
// the program needs and stay on screen until the reader is done.
//
// SafeMirror only ever reads, so the guided session runs its full audit. There
// is nothing here it could damage: every file it touches is opened for reading.
//
// 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("  SafeMirror")
	fmt.Println("  Check whether the backups you already have really cover your files.")
	fmt.Println()
	fmt.Println("  You tell SafeMirror which folder matters and where you believe its")
	fmt.Println("  copies live. It reads every file in both places, compares them, and")
	fmt.Println("  names the files that are short of a good copy — and why.")
	fmt.Println()
	fmt.Println("  It never makes a backup and never changes one. It reads, and reports.")
	fmt.Println()

	path, ok := askSettings(in, suggestedSettings())
	if !ok {
		return
	}

	fmt.Println()
	fmt.Println("  Reading every file and every copy. This is the slow part — on a big")
	fmt.Println("  folder it can take several minutes.")
	fmt.Println()
	runAudit([]string{"--config", path})

	fmt.Println()
	fmt.Println("  Nothing was copied, moved or deleted. SafeMirror only reads.")
	fmt.Println("  There is more at a command prompt — a per-location summary, and a full")
	fmt.Println("  explanation of any single file that surprised you: safemirror --help")
	pause(in)
}

// askSettings asks for the settings file that names the folder and its backup
// locations, and keeps asking until it has one that really exists.
//
// Pressing Enter with nothing to offer is not a dead end: it prints a
// ready-to-edit example instead, which is what somebody opening SafeMirror for
// the first time actually needs.
func askSettings(in *bufio.Scanner, suggested string) (string, bool) {
	for {
		fmt.Println("  Where is your SafeMirror settings file?")
		fmt.Println("  It is the small file that names the folder you care about and the")
		fmt.Println("  places you keep copies of it. You can drag it from Explorer onto")
		fmt.Println("  this window to paste its location.")
		if suggested != "" {
			fmt.Printf("  (press Enter for %s)\n", suggested)
		} else {
			fmt.Println("  (press Enter to see an example you can copy and fill in)")
		}
		fmt.Print("  > ")

		if !in.Scan() {
			// stdin closed on us; there is nothing sensible left to ask.
			return "", false
		}
		answer := strings.Trim(strings.TrimSpace(in.Text()), `"`)
		if answer == "" {
			answer = suggested
		}
		if answer == "" {
			showExample()
			continue
		}

		info, err := os.Stat(answer)
		switch {
		case err != nil:
			fmt.Println()
			fmt.Printf("  I cannot find %q.\n", answer)
			fmt.Println("  Check the location, or press Enter on its own to see an example")
			fmt.Println("  settings file you can copy.")
			fmt.Println()
			continue
		case info.IsDir():
			fmt.Println()
			fmt.Printf("  %q is a folder. I need the settings file itself, the one that\n", answer)
			fmt.Println("  lists your backup locations.")
			fmt.Println()
			continue
		}
		return answer, true
	}
}

// showExample prints a valid settings file for somebody who does not have one
// yet, then leaves them at the prompt to try again.
func showExample() {
	fmt.Println()
	fmt.Println("  You will need a settings file first. Here is a working one — save it")
	fmt.Println("  somewhere as safemirror.json, put your own folders in it, then come")
	fmt.Println("  back and give me its location.")
	fmt.Println()
	runConfig([]string{"--example"})
	fmt.Println()
}

// suggestedSettings looks for a settings file the reader has probably already
// made, so the common case is one keypress. It returns "" when there is
// nothing to offer, and the prompt shows an example instead.
func suggestedSettings() string {
	var dirs []string
	if wd, err := os.Getwd(); err == nil {
		dirs = append(dirs, wd)
	}
	if exe, err := os.Executable(); err == nil {
		dirs = append(dirs, filepath.Dir(exe))
	}
	if home, err := os.UserHomeDir(); err == nil {
		dirs = append(dirs, home,
			filepath.Join(home, "Documents"),
			filepath.Join(home, "Downloads"))
	}
	names := []string{"safemirror.json", "safemirror-config.json", "3-2-1.json"}
	for _, dir := range dirs {
		for _, name := range names {
			candidate := filepath.Join(dir, name)
			if info, err := os.Stat(candidate); err == nil && info.Mode().IsRegular() {
				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()
}
