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.
//
// Guided mode runs the plan, which reads both sides and writes nothing. The
// copying half of PocketSync is never offered here: a person who double-clicked
// an unfamiliar program should get an explanation of what would happen, not
// files appearing in their libraries.
func runGuided() {
	in := bufio.NewScanner(os.Stdin)

	fmt.Println()
	fmt.Println("  PocketSync")
	fmt.Println("  Work out what is missing from each of two photo libraries.")
	fmt.Println()
	fmt.Println("  Give it two folders — an old phone and a new one, say — and it")
	fmt.Println("  compares them file by file: what only the first one has, what only")
	fmt.Println("  the second one has, what was renamed, and where the same file was")
	fmt.Println("  changed on both sides and somebody has to choose.")
	fmt.Println()
	fmt.Println("  This is the report, not the copying. Nothing is written, moved or")
	fmt.Println("  deleted, on either side.")
	fmt.Println()

	sideA := askFolder(in, "Which folder is the FIRST library?", suggestedFolder(), "")
	if sideA == "" {
		return
	}
	sideB := askFolder(in, "And which folder is the SECOND one?", "", sideA)
	if sideB == "" {
		return
	}

	fmt.Println()
	fmt.Println("  Comparing. Every file on both sides has to be read to be sure it")
	fmt.Println("  really is the same file, so a large library can take a few minutes.")
	fmt.Println()
	cmdPlan([]string{"--a", sideA, "--b", sideB})

	fmt.Println()
	fmt.Println("  Run it again any time on another pair of folders.")
	fmt.Println("  There is a command-line version too, which can record a baseline and")
	fmt.Println("  carry the copies out for you: pocketsync help")
	pause(in)
}

// askFolder puts one folder question to the reader and keeps asking until the
// answer is a directory that really exists. It returns "" only when stdin has
// closed and there is nothing sensible left to ask.
//
// notSame, when set, is a folder the answer may not repeat: comparing a library
// against itself is never what anybody meant.
func askFolder(in *bufio.Scanner, question, suggested, notSame string) string {
	for {
		fmt.Println("  " + question)
		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 here. Try again, or close this window.")
			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
		}

		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
		}

		if notSame != "" && sameFolder(answer, notSame) {
			fmt.Println()
			fmt.Println("  That is the same folder you gave me a moment ago. I need two")
			fmt.Println("  different folders to compare.")
			fmt.Println()
			continue
		}

		abs, err := filepath.Abs(answer)
		if err != nil {
			return answer
		}
		return abs
	}
}

// sameFolder reports whether two answers name the same directory, comparing the
// absolute forms so "Pictures" and "C:\Users\me\Pictures" are caught.
func sameFolder(a, b string) bool {
	absA, errA := filepath.Abs(a)
	absB, errB := filepath.Abs(b)
	if errA != nil || errB != nil {
		return a == b
	}
	return absA == absB
}

// suggestedFolder offers a first side that is certain to exist, so the reader
// can accept it with one keypress.
func suggestedFolder() string {
	home, err := os.UserHomeDir()
	if err != nil {
		return ""
	}
	// A phone library copied onto a computer nearly always lands in one of
	// these; there is no honest guess for the second side, so only the first
	// question gets a default.
	for _, name := range []string{"Pictures", "DCIM", "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()
}
