package main

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"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.
//
// 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 two commands that write nothing: the cast summary and
// the moment finder. Writing PNGs is a command-line job.
func runGuided() {
	in := bufio.NewScanner(os.Stdin)

	fmt.Println()
	fmt.Println("  CaptureStudio")
	fmt.Println("  Finds the moments worth a picture in a recorded terminal session.")
	fmt.Println()
	fmt.Println("  Give it a recording and it replays the session on a screen in memory,")
	fmt.Println("  then tells you what the recording contains and exactly when the")
	fmt.Println("  screen settled after each burst of activity — the timestamps where")
	fmt.Println("  something actually happened.")
	fmt.Println()
	fmt.Println("  Nothing is written here. No images, no files.")
	fmt.Println()

	suggested := suggestedCast()
	for {
		fmt.Println("  Which recording shall I look through?")
		if suggested != "" {
			fmt.Printf("  (press Enter for %s)\n", suggested)
		} else {
			fmt.Println("  Tip: you can drag the recording, or the folder holding it, from")
			fmt.Println("  Explorer onto this window to paste its location.")
		}
		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 recording to look through. Try again, or close this")
			fmt.Println("  window. A recording is the .jsonl file SessionForge writes.")
			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 the recording, or the folder holding it, from")
			fmt.Println("  Explorer onto this window to paste its location, then press Enter.")
			fmt.Println()
			continue
		case info.IsDir():
			// A dragged folder is a fair guess at where the recording lives.
			found := castInDir(answer)
			if found == "" {
				fmt.Println()
				fmt.Printf("  %q is a folder, and I found no recording inside it.\n", answer)
				fmt.Println("  Drag the recording file itself onto this window instead.")
				fmt.Println()
				continue
			}
			fmt.Println()
			fmt.Printf("  That is a folder. Using the recording inside it: %s\n", found)
			answer = found
		}

		// Load it here rather than letting the commands do it, because they
		// end an unreadable cast with os.Exit — which would shut the window
		// before the reader could read why.
		c, err := loadCast(answer)
		if err != nil {
			fmt.Println()
			fmt.Printf("  I could not read %s as a recording.\n", filepath.Base(answer))
			fmt.Printf("  %v\n", err)
			fmt.Println()
			fmt.Println("  CaptureStudio reads the .jsonl recordings SessionForge writes.")
			fmt.Println()
			continue
		}
		if len(c.Events) == 0 {
			fmt.Println()
			fmt.Printf("  %s is a valid recording, but nothing was ever recorded in it.\n", filepath.Base(answer))
			fmt.Println()
			continue
		}

		fmt.Println()
		fmt.Println("  Replaying. A long session takes a moment.")
		fmt.Println()
		cmdInfo([]string{answer})
		fmt.Println()
		cmdMoments([]string{answer, "--count", "8"})
		break
	}

	fmt.Println()
	fmt.Println("  Those timestamps are what you would hand to the command-line version")
	fmt.Println("  to turn into PNG stills or one contact sheet: capturestudio help")
	pause(in)
}

// castInDir returns the first recording directly inside dir, or "".
func castInDir(dir string) string {
	entries, err := os.ReadDir(dir)
	if err != nil {
		return ""
	}
	var names []string
	for _, e := range entries {
		if e.IsDir() {
			continue
		}
		switch strings.ToLower(filepath.Ext(e.Name())) {
		case ".jsonl", ".cast":
			names = append(names, e.Name())
		}
	}
	if len(names) == 0 {
		return ""
	}
	sort.Strings(names)
	return filepath.Join(dir, names[0])
}

// suggestedCast offers a recording that is certain to exist, so the reader can
// get going by pressing one key. It returns "" when there is nothing nearby,
// and the prompt asks for a path instead.
func suggestedCast() string {
	var dirs []string
	if wd, err := os.Getwd(); err == nil {
		dirs = append(dirs, wd)
	}
	// The folder the program was double-clicked in is the other likely place
	// for a recording somebody wants pictures of.
	if exe, err := os.Executable(); err == nil {
		dirs = append(dirs, filepath.Dir(exe))
	}
	if home, err := os.UserHomeDir(); err == nil {
		dirs = append(dirs, home,
			filepath.Join(home, "Documents"),
			filepath.Join(home, "Desktop"),
			filepath.Join(home, "Downloads"))
	}
	for _, dir := range dirs {
		if found := castInDir(dir); found != "" {
			return found
		}
	}
	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()
}
