// gummycheck：1B/6B 实测工具——用真实 DashScope Key 验证 gummy provider 全链路。
// 用法（key 经 stdin 传入，不落盘）：
//
//	rbw get dashscope-api-key | go run ./cmd/gummycheck -wav /path/to/16k-mono-16bit.wav
package main

import (
	"bufio"
	"bytes"
	"context"
	"encoding/binary"
	"flag"
	"fmt"
	"os"
	"strings"
	"time"

	"dudu/server/internal/asr"
)

func main() {
	wavPath := flag.String("wav", "", "16kHz/16bit/mono wav 文件路径")
	model := flag.String("model", "gummy-realtime-v1", "DashScope 实时识别模型")
	paceMs := flag.Int("pace", 50, "每 100ms 帧的推流间隔 ms（50=2x 加速，100=实时）")
	idleSec := flag.Int("idle", 0, "会话建立后先闲置 N 秒再推流（测预连接会话的存活时间）")
	flag.Parse()
	if *wavPath == "" {
		fmt.Fprintln(os.Stderr, "用法: rbw get dashscope-api-key | gummycheck -wav test.wav")
		os.Exit(2)
	}

	sc := bufio.NewScanner(os.Stdin)
	if !sc.Scan() {
		fmt.Fprintln(os.Stderr, "stdin 未读到 API key")
		os.Exit(2)
	}
	key := strings.TrimSpace(sc.Text())

	pcm, err := readWavData(*wavPath)
	if err != nil {
		fmt.Fprintln(os.Stderr, "读 wav 失败:", err)
		os.Exit(1)
	}
	fmt.Printf("音频 %d 字节 ≈ %.1fs\n", len(pcm), float64(len(pcm))/32000)

	p := asr.NewGummy(key)
	p.Model = *model
	fmt.Printf("模型 %s · 推流间隔 %dms/帧\n", *model, *paceMs)
	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
	defer cancel()

	start := time.Now()
	sess, err := p.StartSession(ctx, asr.SessionConfig{SampleRate: 16000, SessionID: "gummycheck"})
	if err != nil {
		fmt.Fprintln(os.Stderr, "StartSession 失败:", err)
		os.Exit(1)
	}
	fmt.Printf("会话建立 %v\n", time.Since(start).Round(time.Millisecond))
	if *idleSec > 0 {
		fmt.Printf("闲置 %ds...\n", *idleSec)
		time.Sleep(time.Duration(*idleSec) * time.Second)
		start = time.Now() // 重新计时，测闲置后的识别延迟
	}

	done := make(chan struct{})
	var firstPartial time.Duration
	go func() {
		defer close(done)
		for r := range sess.Results() {
			if r.Err != nil {
				fmt.Println("ERROR:", r.Err)
				return
			}
			if firstPartial == 0 {
				firstPartial = time.Since(start)
			}
			tag := "partial"
			if r.IsFinal {
				tag = "FINAL  "
			}
			fmt.Printf("[%6.2fs] %s end=%dms  %s\n", time.Since(start).Seconds(), tag, r.EndTimeMs, r.Text)
		}
	}()

	const frame = 3200
	for off := 0; off < len(pcm); off += frame {
		end := min(off+frame, len(pcm))
		if err := sess.SendAudio(pcm[off:end]); err != nil {
			fmt.Fprintln(os.Stderr, "SendAudio 失败:", err)
			os.Exit(1)
		}
		time.Sleep(time.Duration(*paceMs) * time.Millisecond)
	}
	_ = sess.Close()
	<-done
	fmt.Printf("首个结果延迟 %v（推流 %dms/帧）\n", firstPartial.Round(time.Millisecond), *paceMs)
}

// readWavData 提取 wav 的 data chunk（仅支持 PCM）。
func readWavData(path string) ([]byte, error) {
	b, err := os.ReadFile(path)
	if err != nil {
		return nil, err
	}
	if len(b) < 44 || string(b[0:4]) != "RIFF" || string(b[8:12]) != "WAVE" {
		return nil, fmt.Errorf("不是 wav 文件")
	}
	off := 12
	for off+8 <= len(b) {
		id := string(b[off : off+4])
		size := int(binary.LittleEndian.Uint32(b[off+4 : off+8]))
		if id == "data" {
			return b[off+8 : min(off+8+size, len(b))], nil
		}
		off += 8 + size
	}
	return nil, fmt.Errorf("未找到 data chunk")
}

var _ = bytes.MinRead
