package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strings"
)

// runGuided is what happens when somebody double-clicks DeskPilot 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 DeskPilot needs and stay on screen until the reader is done.
//
// The guided session shows what is saved and previews what a workspace would
// open. It launches nothing: no browser window, no program, no file. Opening a
// workspace for real is one short command away, and it should be the reader's
// decision rather than a side effect of double-clicking.
func runGuided() {
	in := bufio.NewScanner(os.Stdin)

	fmt.Println()
	fmt.Println("  DeskPilot")
	fmt.Println("  Save the set of things you open every morning, then open them together.")
	fmt.Println()
	fmt.Println("  A workspace is a named list: the web pages, folders and programs that")
	fmt.Println("  belong to one job. I will show you the workspaces saved on this")
	fmt.Println("  machine, and walk through exactly what one of them would open.")
	fmt.Println()
	fmt.Println("  Nothing is launched here, and nothing is saved or changed.")
	fmt.Println()

	dir, ok := askWorkspaceDir(in)
	if !ok {
		return
	}

	fmt.Println()
	cmdList([]string{"--dir", dir})

	names := workspaceNames(dir)
	if len(names) > 0 {
		fmt.Println()
		previewWorkspace(in, dir, names)
	} else {
		fmt.Println()
		fmt.Println("  Once you save a workspace, this is where it will appear.")
	}

	fmt.Println()
	fmt.Println("  Done. Nothing was opened — this session only looks.")
	fmt.Println("  Saving a new workspace, and opening one for real, are two short")
	fmt.Println("  commands: run deskpilot --help to see them.")
	pause(in)
}

// askWorkspaceDir asks where the workspaces are kept. The default is the
// folder DeskPilot itself uses, which on a machine that has never saved one
// does not exist yet — that is an ordinary state of affairs, not an error, so
// accepting the default is always allowed. A folder the reader typed has to be
// real, and they get another go at it.
func askWorkspaceDir(in *bufio.Scanner) (string, bool) {
	suggested := suggestedWorkspaceDir()
	for {
		fmt.Println("  Where are your workspaces kept?")
		if suggested != "" {
			fmt.Printf("  (press Enter for %s, where DeskPilot puts them)\n", suggested)
		}
		fmt.Println("  Tip: you can drag a folder from Explorer onto this window to")
		fmt.Println("  paste its location, then press Enter.")
		fmt.Print("  > ")

		if !in.Scan() {
			// stdin closed on us; there is nothing sensible left to ask.
			return "", false
		}
		answer := strings.TrimSpace(in.Text())
		answer = strings.Trim(answer, `"`)
		accepted := answer == ""
		if accepted {
			answer = suggested
		}
		if answer == "" {
			fmt.Println()
			fmt.Println("  I need a folder to look in. Try again, or close this window.")
			fmt.Println()
			continue
		}

		info, err := os.Stat(answer)
		switch {
		case err != nil && accepted:
			// The usual folder is simply not there yet, because nobody has
			// saved a workspace on this machine. cmdList says so kindly.
			return answer, true
		case err != nil:
			fmt.Println()
			fmt.Printf("  I cannot find %q.\n", answer)
			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, true
	}
}

// previewWorkspace asks which saved workspace to walk through and prints what
// opening it would do, item by item. Nothing is launched.
func previewWorkspace(in *bufio.Scanner, dir string, names []string) {
	for {
		fmt.Println("  Which one shall I walk through?")
		fmt.Printf("  (press Enter for %s — nothing will be opened)\n", names[0])
		fmt.Print("  > ")

		if !in.Scan() {
			return
		}
		answer := strings.TrimSpace(in.Text())
		answer = strings.Trim(answer, `"`)
		if answer == "" {
			answer = names[0]
		}
		if _, err := loadWorkspace(dir, answer); err != nil {
			fmt.Println()
			fmt.Printf("  There is no workspace called %q here.\n", answer)
			fmt.Printf("  The ones I can see are: %s\n", strings.Join(names, ", "))
			fmt.Println()
			continue
		}

		fmt.Println()
		cmdOpen([]string{"--dir", dir, "--dry-run", answer})
		return
	}
}

// workspaceNames lists the workspaces saved in dir, in the order the reader
// sees them. An unreadable or absent folder simply has none.
func workspaceNames(dir string) []string {
	entries, err := os.ReadDir(dir)
	if err != nil {
		return nil
	}
	var names []string
	for _, e := range entries {
		if e.IsDir() || !strings.HasSuffix(e.Name(), ".json") {
			continue
		}
		names = append(names, strings.TrimSuffix(e.Name(), ".json"))
	}
	sort.Strings(names)
	return names
}

// suggestedWorkspaceDir offers the folder DeskPilot saves workspaces in, so
// the reader can get going with one keypress. It may not exist yet on a fresh
// machine, which the prompt handles rather than treating as an error.
func suggestedWorkspaceDir() string {
	return defaultDir()
}

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