package main

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

// runGuided is what happens when somebody double-clicks DeskAutomate instead
// of typing its name at a prompt.
//
// Explorer opens a console, runs the program with no arguments, and destroys
// the window the instant the process exits — so printing usage and quitting
// looks exactly like a crash. When we know we were double-clicked we ask the
// one thing DeskAutomate needs and stay on screen until the reader is done.
//
// The guided session checks the rules and explains them. It does not start
// watching and it fires no rule, so no file is moved, copied or renamed and no
// command is run. Watching is a deliberate command-line act: it is a
// long-running program that acts on its own.
func runGuided() {
	in := bufio.NewScanner(os.Stdin)

	fmt.Println()
	fmt.Println("  DeskAutomate")
	fmt.Println("  Check your filing rules before you set them loose.")
	fmt.Println()
	fmt.Println("  DeskAutomate watches folders and files things for you: a PDF lands in")
	fmt.Println("  your inbox folder and it gets moved where it belongs. The rules live")
	fmt.Println("  in a file. Give me that file and I will check every rule reads")
	fmt.Println("  properly, then tell you in plain words what each one watches for and")
	fmt.Println("  what it would do.")
	fmt.Println()
	fmt.Println("  No watching starts here and no rule fires. Nothing is moved or changed.")
	fmt.Println()

	suggested := suggestedRulesFile()
	for {
		fmt.Println("  Where is your rules file?")
		if suggested != "" {
			fmt.Printf("  (press Enter for %s)\n", suggested)
		} else {
			fmt.Println("  (it is a .json file listing your rules)")
		}
		fmt.Println("  Tip: you can drag the file, or the folder it lives in, from Explorer")
		fmt.Println("  onto this window to paste its location, then press Enter.")
		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 rules file to read. 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()
			continue
		case info.IsDir():
			// A dragged folder is an ordinary mistake: look for the obvious
			// file inside it before complaining about it.
			inside := filepath.Join(answer, "rules.json")
			if fi, err := os.Stat(inside); err == nil && !fi.IsDir() {
				fmt.Println()
				fmt.Printf("  That is a folder — I will use %s inside it.\n", inside)
				answer = inside
				break // leaves the switch, and carries on with the file below
			}
			fmt.Println()
			fmt.Printf("  %q is a folder. I need the rules file itself, which ends in .json.\n", answer)
			fmt.Println()
			continue
		}

		if _, err := loadRules(answer); err != nil {
			fmt.Println()
			fmt.Println("  I could not read that as a rules file.")
			fmt.Printf("  %v\n", err)
			fmt.Println()
			continue
		}

		fmt.Println()
		// cmdRules is the read-only half of DeskAutomate: it validates the
		// file and lists the rules. It returns a code rather than exiting, so
		// an invalid file leaves the window open with the reasons on screen.
		cmdRules([]string{answer})
		break
	}

	fmt.Println()
	fmt.Println("  Done. Nothing was watched and no rule ran — that was a read of the")
	fmt.Println("  rules file, no more.")
	fmt.Println("  Setting the watcher running is a separate command-line step, and even")
	fmt.Println("  then it previews what it would do until you tell it otherwise:")
	fmt.Println("  run deskautomate --help to see it.")
	pause(in)
}

// suggestedRulesFile offers a rules file the reader can accept with one
// keypress: the obvious one next to the program itself, or in the folder the
// console opened in. It returns "" when there is no such file, and the prompt
// copes with that.
func suggestedRulesFile() string {
	var dirs []string
	if exe, err := os.Executable(); err == nil {
		dirs = append(dirs, filepath.Dir(exe))
	}
	if wd, err := os.Getwd(); err == nil {
		dirs = append(dirs, wd)
	}
	for _, dir := range dirs {
		for _, name := range []string{"rules.json", "deskautomate.json"} {
			candidate := filepath.Join(dir, name)
			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()
}
