package main

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

// guidedDuration is how long each benchmark phase runs in the guided session.
// The command line defaults to 500ms per phase; a double-clicked window is
// somebody watching a blank screen, so the guided round is deliberately short
// — two phases at 250ms plus start-up is over in about a second, and the
// single-thread/multi-thread ratio it measures is the same one the longer run
// reports. The reader who wants a longer, steadier measurement can pass
// --duration from a command prompt.
const guidedDuration = 250 * time.Millisecond

// historyFileName is the file ThermalFlow keeps its measurements in when the
// reader accepts the offered default.
const historyFileName = "thermalflow-history.jsonl"

// 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.
//
// 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.
//
// The only thing this session writes is ThermalFlow's own history file, which
// is append-only: one line per measurement, nothing ever removed or rewritten.
// Nothing else on the machine is touched.
func runGuided() {
	in := bufio.NewScanner(os.Stdin)

	fmt.Println()
	fmt.Println("  ThermalFlow")
	fmt.Println("  Is this computer still as fast as it used to be?")
	fmt.Println()
	fmt.Println("  It runs a short CPU speed test — once using one core, then using")
	fmt.Println("  all of them — writes the score into a history file, and compares")
	fmt.Println("  today's score against the ones already in that file. Run it every")
	fmt.Println("  week or two and the history tells you whether the machine is")
	fmt.Println("  slowing down.")
	fmt.Println()
	fmt.Println("  It reads and writes one small text file of scores, and nothing else.")
	fmt.Println()

	suggested := suggestedHistoryFile()
	var history string
	for {
		fmt.Println("  Where shall I keep the history of scores?")
		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 somewhere to keep the scores. Try again, or close this")
			fmt.Println("  window.")
			fmt.Println()
			continue
		}

		// A folder is a perfectly reasonable answer — and it is what you get
		// when a folder is dragged in from Explorer — so put the history file
		// inside it rather than complaining.
		if info, err := os.Stat(answer); err == nil && info.IsDir() {
			answer = filepath.Join(answer, historyFileName)
		}

		parent := filepath.Dir(answer)
		info, err := os.Stat(parent)
		switch {
		case err != nil:
			fmt.Println()
			fmt.Printf("  I cannot find the folder %q.\n", parent)
			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, so I cannot put the history in it.\n", parent)
			fmt.Println()
			continue
		}
		if info, err := os.Stat(answer); err == nil && info.IsDir() {
			fmt.Println()
			fmt.Printf("  %q is a folder. Give me a file name to keep the scores in.\n", answer)
			fmt.Println()
			continue
		}

		history = answer
		break
	}

	fmt.Println()
	if info, err := os.Stat(history); err == nil && info.Size() > 0 {
		fmt.Printf("  Adding to the history already in %s.\n", history)
	} else {
		fmt.Printf("  Starting a new history in %s.\n", history)
		fmt.Println("  The first run has nothing to compare against yet — run it again")
		fmt.Println("  in a week or two and it will.")
	}
	fmt.Println()
	fmt.Println("  Measuring. This takes about a second; leave the machine alone")
	fmt.Println("  while it runs, or the score will be low for the wrong reason.")
	fmt.Println()

	cmdRun([]string{"--history", history, "--duration", guidedDuration.String()})

	fmt.Println()
	fmt.Println("  ---- the history so far ----")
	fmt.Println()
	cmdTrend([]string{"--history", history, "--last", "10"})

	fmt.Println()
	fmt.Println("  Done. Run it again in a week and the comparison gets more useful.")
	fmt.Println("  There is a command-line version too, which can run a longer test")
	fmt.Println("  and check itself on a schedule: thermalflow --help")
	pause(in)
}

// suggestedHistoryFile offers a place for the score history that is certain to
// be writable, so the reader can get a useful answer by pressing one key.
func suggestedHistoryFile() string {
	home, err := os.UserHomeDir()
	if err != nil {
		return ""
	}
	if info, err := os.Stat(home); err != nil || !info.IsDir() {
		return ""
	}
	return filepath.Join(home, historyFileName)
}

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