1"use client"
2
3import { useCallback, useEffect, useRef, type RefObject } from "react"
4import type Webcam from "react-webcam"
5
6import { captureClipFrame } from "@/features/camera/captureFrame"
7
8import { CLIP_FRAME_WIDTH, planClipRecording } from "./clipRecorder"
9import type { CapturePhase } from "./machine"
10
11/* SH-01: perekam bingkai klip. Hook ini hanya mengamati fase hitung mundur:
12 tiap offset dari `planClipRecording` menjadwalkan satu bingkai, dan semua
13 promise-nya ditunggu di `takeFrames` saat foto utama disimpan. Tidak ada
14 event mesin yang dikirim dari sini, jadi waktu foto utama tidak berubah. */
15
16export function useClipRecorder({
17 webcamRef,
18 slotRatio,
19 phase,
20}: {
21 webcamRef: RefObject<Webcam | null>
22 /** Rasio slot layout terpilih; `null` berarti layout belum dipilih. */
23 slotRatio: number | null
24 phase: CapturePhase
25}): () => Promise<ImageBitmap[]> {
26 const pendingRef = useRef<Promise<ImageBitmap | null>[]>([])
27
28 useEffect(() => {
29 if (phase !== "countdown" || slotRatio === null) {
30 return
31 }
32 const video = webcamRef.current?.video ?? null
33 if (video === null) {
34 return
35 }
36 const { sampleOffsetsMs } = planClipRecording()
37 const timers = sampleOffsetsMs.map((offset) =>
38 window.setTimeout(() => {
39 pendingRef.current.push(
40 captureClipFrame(video, slotRatio, CLIP_FRAME_WIDTH)
41 )
42 }, offset)
43 )
44 return () => {
45 for (const timer of timers) {
46 window.clearTimeout(timer)
47 }
48 }
49 }, [phase, slotRatio, webcamRef])
50
51 /* Bingkai yang masih diproses ditunggu di sini, bukan di timer: fase
52 `capturing` tidak punya timer sendiri, jadi menunggunya tidak menunda
53 apa pun kecuali penyimpanan foto. */
54 return useCallback(async () => {
55 const pending = pendingRef.current
56 pendingRef.current = []
57 const settled = await Promise.allSettled(pending)
58 const frames: ImageBitmap[] = []
59 for (const result of settled) {
60 if (result.status === "fulfilled" && result.value !== null) {
61 frames.push(result.value)
62 }
63 }
64 return frames
65 }, [])
66}
67