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 surveys and reports, and stops there. SnapDocs writes
// files — a steps file, a finished document — and writing files is not
// something anyone should trigger by double-clicking an icon and pressing
// Enter. So this shows what is there and what a build would make of it, and
// leaves the writing to the command line, typed on purpose.
//
// 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("  SnapDocs")
	fmt.Println("  Turn a folder of screenshots into one document you can send anyone.")
	fmt.Println()
	fmt.Println("  Show me the folder your screenshots are in. I will list them in the")
	fmt.Println("  order they would appear, and if you have already written the notes")
	fmt.Println("  that go with them I will check those against the pictures too.")
	fmt.Println()
	fmt.Println("  It only reads. No document is written and no image is modified.")
	fmt.Println()

	suggested := suggestedFolder()
	var dir string
	for {
		fmt.Println("  Which folder are your screenshots in?")
		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 a folder to look at. 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
		}
		dir = answer
		break
	}

	fmt.Println()
	fmt.Println("  Working. Every picture is opened to read its size.")
	fmt.Println()
	reportFolder(dir)

	fmt.Println()
	fmt.Println("  Done. Nothing was written.")
	fmt.Println("  The command-line version writes the steps file and builds the")
	fmt.Println("  finished document: snapdocs help")
	pause(in)
}

// reportFolder prints the image inventory a build would work from, and — when
// the notes have already been written — the same validation the check command
// performs. It uses the program's own scanning and validation, so what the
// reader sees here is what a build would see.
func reportFolder(dir string) {
	abs, err := filepath.Abs(dir)
	if err != nil {
		abs = dir
	}

	images, bad, err := scanImages(abs)
	if err != nil {
		fmt.Printf("  I could not read %s: %v\n", abs, err)
		return
	}

	var total int64
	for _, im := range images {
		total += im.size
	}
	fmt.Printf("  Folder      : %s\n", abs)
	fmt.Printf("  Screenshots : %d (%s)\n\n", len(images), humanBytes(total))

	if len(images) == 0 {
		fmt.Println("  I found no pictures in there. SnapDocs reads .png, .jpg, .jpeg")
		fmt.Println("  and .gif files. Check you gave me the right folder.")
		return
	}

	fmt.Println("  In the order they would appear:")
	for i, im := range images {
		fmt.Printf("  %3d. %-30s %dx%d %s %s\n", i+1, im.name, im.width, im.height,
			strings.ToUpper(im.format), humanBytes(im.size))
	}
	for _, b := range bad {
		fmt.Printf("       skipping %s: %v\n", b.name, b.err)
	}

	fmt.Println()
	stepsPath, err := resolveSteps(abs, "steps.txt")
	if err != nil {
		fmt.Println("  You have not written the notes for these yet — there is no")
		fmt.Println("  steps.txt in that folder. The command-line version can write a")
		fmt.Println("  starter one for you with a blank stanza per picture, ready to")
		fmt.Println("  fill in.")
		return
	}

	parsed, err := parseSteps(stepsPath)
	if err != nil {
		fmt.Printf("  I found %s but could not read it:\n", stepsPath)
		fmt.Printf("  %v\n", err)
		return
	}

	probs := validate(parsed, images, bad, abs)
	fmt.Printf("  Notes       : %d step(s) in %s\n\n", len(parsed), stepsPath)
	if len(probs) == 0 {
		fmt.Println("  No problems found. This folder is ready to build.")
		return
	}
	fmt.Printf("  %d problem(s) to fix first:\n", len(probs))
	for _, p := range probs {
		fmt.Printf("    [%s] %s\n", p.kind, p.detail)
	}
}

// suggestedFolder offers somewhere screenshots really land, so the reader can
// get a useful answer by pressing one key.
func suggestedFolder() string {
	home, err := os.UserHomeDir()
	if err != nil {
		return ""
	}
	// Windows saves screenshots under Pictures\Screenshots by default; the
	// deeper, more specific folder is the better guess when it is there.
	for _, parts := range [][]string{
		{"Pictures", "Screenshots"},
		{"Pictures"},
		{"Desktop"},
	} {
		candidate := filepath.Join(append([]string{home}, parts...)...)
		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()
}
