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 two
// questions 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("  FindPilot")
	fmt.Println("  Find a file when you can only remember part of it.")
	fmt.Println()
	fmt.Println("  Tell it where to look and what to look for. It checks every file")
	fmt.Println("  name in that folder and everything below it, then reads the text")
	fmt.Println("  files themselves and shows you the lines that mention it.")
	fmt.Println()
	fmt.Println("  It only reads. Nothing is moved, changed or deleted.")
	fmt.Println()

	folder := askFolder(in)
	if folder == "" {
		return
	}
	term := askSearchTerm(in)
	if term == "" {
		return
	}

	fmt.Println()
	fmt.Println("  Working. On a large folder this can take a minute.")
	fmt.Println()
	fmt.Println("  Files whose name mentions it")
	fmt.Println("  ----------------------------")
	cmdSearch([]string{folder, "--name", "*" + term + "*"})

	fmt.Println()
	fmt.Println("  Lines inside files that mention it")
	fmt.Println("  ----------------------------------")
	cmdSearch([]string{folder, "--content", term, "--ignore-case", "--max", "50"})

	fmt.Println()
	fmt.Println("  Done. Run it again any time on another folder.")
	fmt.Println("  There is a command-line version too: findpilot --help")
	pause(in)
}

// askFolder asks where to search and keeps asking until the answer is a real
// folder, so the search never starts on a path that cannot work. It returns ""
// only when stdin closes, which means there is nobody left to ask.
func askFolder(in *bufio.Scanner) string {
	suggested := suggestedFolder()
	for {
		fmt.Println("  Which folder shall I search?")
		if suggested != "" {
			fmt.Printf("  (press Enter for %s)\n", suggested)
		}
		fmt.Print("  > ")

		if !in.Scan() {
			return ""
		}
		answer := strings.TrimSpace(in.Text())
		answer = strings.Trim(answer, `"`)
		if answer == "" {
			answer = suggested
		}
		if answer == "" {
			fmt.Println()
			fmt.Println("  I need a folder to search. 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. Give me the folder it sits in.\n", answer)
			fmt.Println()
			continue
		}
		return answer
	}
}

// askSearchTerm asks what to look for. An empty search would match every file
// in the tree and print pages of noise, so it is refused rather than run.
func askSearchTerm(in *bufio.Scanner) string {
	for {
		fmt.Println()
		fmt.Println("  What shall I look for? A word or part of a name is enough.")
		fmt.Print("  > ")

		if !in.Scan() {
			return ""
		}
		answer := strings.TrimSpace(in.Text())
		answer = strings.Trim(answer, `"`)
		if answer != "" {
			return answer
		}
		fmt.Println()
		fmt.Println("  I need something to look for. Try again, or close this window.")
	}
}

// suggestedFolder offers somewhere worth searching that is certain to exist,
// so the reader can get a useful answer by pressing one key.
func suggestedFolder() string {
	home, err := os.UserHomeDir()
	if err != nil {
		return ""
	}
	// A home directory is the honest default, but the file somebody has
	// actually mislaid is usually one they saved or downloaded themselves.
	for _, name := range []string{"Documents", "Downloads"} {
		candidate := filepath.Join(home, name)
		if info, err := os.Stat(candidate); err == nil && info.IsDir() {
			return candidate
		}
	}
	return home
}

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