package main

//
// Example: Record from an LT device input
//
// This example demonstrates how to:
//      1. Connect to a given input source on an LT device.
//      2. Verify that the source has a locked video signal.
//      3. Create a worker to record the input in MP4 format.
//      4. Save the recording to the current working directory.
//      5. Capture keyboard events to control the recording:
//         - space key : start/pause recording
//         - any other key : stop recording
//
// The recording is configured for a total duration of 20 seconds with file splits every 6 seconds.
//
// Usage:
//      record.exe -source <sourceURL>
//
// Arguments:
//      -source, -s    URL of a valid LT device input, for example:
//                         lt310:/0/hdmi-in/0
//                         lt310:/0/sdi-in/1
//
// Note:
//      This code is intended for demonstration purposes. For production use,
//      ensure proper error handling and resource cleanup.
//
// © 2025 Enciris Technologies. All rights reserved.
//

import (
	"bufio"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"os"
	"strings"

	"golang.org/x/term"

	lt "lt/client/go"
)

var argUsage = `
Arguments:
    -source <String>   URL of a valid LT device input (e.g. lt310:/0/sdi-in/0)

This example verifies that the selected input source is active
and starts a recording (mp4), capturing keyboard events to control the recording.
`

func main() {
	// Command-line flags
	flag.Usage = func() {
		fmt.Printf("Usage:\n    %s -source <sourceURL>\n", os.Args[0])
		fmt.Print(argUsage)
		os.Exit(1)
	}

	var sourceURL string
	flag.StringVar(&sourceURL, "source", "", "Source URL (e.g. lt310:/0/hdmi-in/0)")
	flag.Parse()

	if sourceURL == "" {
		flag.Usage()
	}

	// Create LT client
	var client lt.Client
	defer client.Close()

	// -------------------------------------------------------------------------
	// Check if input selected is active
	// -------------------------------------------------------------------------
	var input lt.Input
	if err := client.Get(sourceURL, &input); err != nil {
		fmt.Printf("%v\n", err)
		return
	}
	if input.Video.Signal != "locked" {
		fmt.Println("Error: input selected is not locked")
		return
	}

	// -------------------------------------------------------------------------
	// Starts recording
	// -------------------------------------------------------------------------
	// Select an absolute path to a capture directory
	wd, err := os.Getwd() // Current working directory
	if err != nil {
		fmt.Printf("working directory: %v\n", err)
		return
	}

	// Create worker
	err = client.Post(sourceURL+"/file", lt.VideoFileWorker{Media: "video/mp4", Location: wd, Duration: 20, SplitDuration: 6}, nil)
	if !errors.Is(err, lt.ErrRedirect) {
		fmt.Printf("worker creation failed: %v\n", err)
		return
	}
	workerURL := lt.RedirectLocation(err)

	// -------------------------------------------------------------------------
	// Capture keyboard events
	//   - space key : start/pause recording
	//   - any other key : stop recording
	// -------------------------------------------------------------------------
	// Allow terminal keyboard events
	state, err := term.MakeRaw(int(os.Stdin.Fd()))
	if err != nil {
		fmt.Printf("failed to set terminal to raw mode: %v\n", err)
		return
	}
	defer term.Restore(int(os.Stdin.Fd()), state)

	// Capture keyboard events
	events := make(chan byte, 1)
	go func() {
		reader := bufio.NewReader(os.Stdin)
		for {
			c, err := reader.ReadByte()
			if err != nil {
				fmt.Printf("failed to read stdin: %v\n", err)
				return
			}
			// Ctrl+C
			// if c == 0x03 {
			// 	fmt.Println("")
			// return
			// }
			// Forward event
			events <- c
		}
	}()
	fmt.Printf("Press SPACE to start/pause recording, any other key to stop.\n\n")

	// -------------------------------------------------------------------------
	// Main loop
	//  - process keyboard events
	//  - monitor recording status
	// -------------------------------------------------------------------------
	var paused bool
	var recordSize int
	var running = true
	for running {
		select {
		case c := <-events:
			switch c {
			// Start/Pause (space key)
			case ' ':
				if paused {
					// Start
					if err := client.Post(workerURL+"/start", nil, nil); err != nil {
						fmt.Printf("failed to start worker: %v\n", err)
						return
					}
					paused = false
				} else {
					// Pause
					if err := client.Post(workerURL+"/pause", nil, nil); err != nil {
						fmt.Printf("failed to pause worker: %v\n", err)
						return
					}
					paused = true
				}

			// Stop (any other key)
			default:
				if err := client.Post(workerURL+"/stop", nil, nil); err != nil {
					fmt.Printf("failed to stop worker: %v\n", err)
					return
				}
				fmt.Printf("\nRecording stopped by user.\n")
			}

		default:
			// Fetch worker response
			var worker lt.Worker
			if err := client.Get(workerURL, &worker); err != nil {
				if errors.Is(err, lt.EOF) {
					running = false
				} else {
					fmt.Printf("\nfailed to get worker: %v\n", err)
					return
				}
			}

			// Process all packets (display only video packet info)
			for _, packet := range worker.Packets {
				if strings.Split(packet.Media, "/")[0] == "video" {
					var meta lt.VideoMetadata
					if err := json.Unmarshal(packet.Meta, &meta); err != nil {
						fmt.Printf("worker packet metadata: %v\n", err)
						return
					}
					fmt.Printf("\r%s %s %dx%d %d bytes", sourceURL, worker.Name, meta.Size[0], meta.Size[1], worker.Length-recordSize)
				}

				// Release packet
				if err := packet.Close(); err != nil {
					fmt.Printf("failed to close packet: %v\n", err)
					return
				}
			}

			// When status is "completed", the current file is closed (either due to split or worker stopped)
			// Save the total recording size and print a new line for the next file
			if worker.Status == "completed" {
				recordSize = worker.Length
				fmt.Println()
			}
		}
	}
	fmt.Printf("\nRecording saved successfully.\n")
}
