// Package rtspgrab captures single frames from the DWARF telescope's RTSP
// server. The telescope's RTSP implementation is non-standard: ffmpeg can
// connect and capture frames but does not terminate cleanly (it hangs after
// writing the output file). This package works around that by launching ffmpeg
// in the background, watching for the output file to appear, then killing ffmpeg.
package rtspgrab

import (
	"context"
	"fmt"
	"image"
	_ "image/jpeg"
	"os"
	"os/exec"
	"time"
)

// GrabFrame connects to the RTSP URL, captures one MJPEG frame, saves it to
// outFile, and returns the decoded image. It uses ffmpeg with low-latency
// options required by the DWARF telescope's non-standard RTSP server, then
// kills ffmpeg once the output file is written (ffmpeg hangs after capture).
func GrabFrame(rtspURL, outFile string) (image.Image, error) {
	// Remove any stale output.
	os.Remove(outFile)

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	cmd := exec.CommandContext(ctx, "ffmpeg",
		"-rtsp_transport", "tcp",
		"-fflags", "nobuffer",
		"-flags", "low_delay",
		"-probesize", "4096",
		"-analyzeduration", "1000000",
		"-i", rtspURL,
		"-frames:v", "1", "-q:v", "2", "-y", outFile)
	cmd.Stdout = nil
	cmd.Stderr = nil

	if err := cmd.Start(); err != nil {
		return nil, fmt.Errorf("start ffmpeg: %w", err)
	}

	// Poll for the output file. Once it appears with non-zero size, kill ffmpeg.
	deadline := time.Now().Add(25 * time.Second)
	for time.Now().Before(deadline) {
		if info, err := os.Stat(outFile); err == nil && info.Size() > 0 {
			// File written — kill ffmpeg (it won't exit on its own).
			cmd.Process.Kill()
			cmd.Wait()
			break
		}
		select {
		case <-ctx.Done():
			cmd.Process.Kill()
			return nil, fmt.Errorf("timeout waiting for frame")
		case <-time.After(200 * time.Millisecond):
		}
	}

	// Check if we got the file.
	info, err := os.Stat(outFile)
	if err != nil || info.Size() == 0 {
		cmd.Process.Kill()
		return nil, fmt.Errorf("no frame captured (ffmpeg produced no output)")
	}

	// Decode the JPEG.
	f, err := os.Open(outFile)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	img, _, err := image.Decode(f)
	if err != nil {
		return nil, fmt.Errorf("decode JPEG: %w", err)
	}
	return img, nil
}
