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.
//
// The guided session reads the store and nothing else. Restoring writes files
// back over a live driver store, which is the single most consequential thing
// this program can do; it is not something to walk somebody into two keypresses
// after they double-clicked an icon. Restoring stays on the command line, where
// the plan can be read first.
//
// 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("  DriverRollback")
	fmt.Println("  Your saved restore points, and what is in them.")
	fmt.Println()
	fmt.Println("  Before a driver update goes wrong, this program takes a complete")
	fmt.Println("  copy of the driver folder and keeps it in a store. Point it at")
	fmt.Println("  that store and it lists every restore point you have: when it was")
	fmt.Println("  taken, how many files it holds, and how much room the store saved")
	fmt.Println("  by not keeping the same file twice.")
	fmt.Println()
	fmt.Println("  It only reads. Nothing is restored, written or removed.")
	fmt.Println()

	suggested := suggestedStore()
	for {
		fmt.Println("  Which store folder shall I read?")
		if suggested != "" {
			fmt.Printf("  (press Enter for %s)\n", suggested)
		}
		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 the folder your restore points are kept in. It is the")
			fmt.Println("  one you passed to --store when you took them, and it is")
			fmt.Println("  called .store unless you chose another name.")
			fmt.Println("  Try again, or close this window.")
			fmt.Println()
			continue
		}

		info, err := os.Stat(answer)
		switch {
		case err != nil:
			fmt.Println()
			fmt.Printf("  I cannot find %q.\n", answer)
			fmt.Println("  Tip: you can drag a folder from Explorer onto this window to")
			fmt.Println("  paste its location, then press Enter.")
			fmt.Println()
			continue
		case !info.IsDir():
			fmt.Println()
			fmt.Printf("  %q is a file, not a folder. A store is a folder.\n", answer)
			fmt.Println()
			continue
		case !looksLikeStore(answer):
			fmt.Println()
			fmt.Printf("  %q does not look like a DriverRollback store.\n", answer)
			fmt.Println("  A store has a snapshots folder inside it. If you have never")
			fmt.Println("  taken a restore point on this machine there is nothing to")
			fmt.Println("  list yet.")
			fmt.Println("  Try another folder, or close this window.")
			fmt.Println()
			continue
		}

		fmt.Println()
		cmdList([]string{"--store", answer})
		break
	}

	fmt.Println()
	fmt.Println("  Done. Nothing was changed — that is just a list of what you have.")
	fmt.Println("  The command-line version can compare two restore points and put a")
	fmt.Println("  folder back the way one of them describes: driverrollback --help")
	pause(in)
}

// suggestedStore offers a store the reader can accept with one keypress, but
// only when one is actually there: the default store name is a folder in the
// working directory, and offering it when it does not exist would send the
// very first keypress straight into an error.
func suggestedStore() string {
	candidates := []string{defaultStore}
	if home, err := os.UserHomeDir(); err == nil {
		candidates = append(candidates, filepath.Join(home, defaultStore))
	}
	for _, c := range candidates {
		if looksLikeStore(c) {
			abs, err := filepath.Abs(c)
			if err != nil {
				return c
			}
			return abs
		}
	}
	return ""
}

// looksLikeStore reports whether a directory is a store somebody has actually
// taken a restore point into, using the engine's own idea of where snapshots
// live. It is what stops the reader being offered a folder that would answer
// "no snapshots yet" and leave them none the wiser about why.
func looksLikeStore(dir string) bool {
	s, err := openStore(dir)
	if err != nil {
		return false
	}
	info, err := os.Stat(s.snapshotsDir())
	return err == nil && info.IsDir()
}

// 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()
}
