package audio

import (
	"bytes"
	"context"
	"io"
	"os"
	"testing"
	"time"
)

func TestPlayWav(t *testing.T) {
	// 跳过测试如果没有测试文件
	testFile := "testdata/test.wav"
	if _, err := os.Stat(testFile); os.IsNotExist(err) {
		t.Skip("测试文件不存在:", testFile)
	}

	f, err := os.Open(testFile)
	if err != nil {
		t.Fatalf("打开测试文件失败: %v", err)
	}
	defer f.Close()

	ctx := context.Background()
	err = PlayWav(ctx, f)
	if err != nil {
		t.Fatalf("PlayWav 失败: %v", err)
	}
}

func TestPlayMP3(t *testing.T) {
	testFile := "testdata/test.mp3"
	if _, err := os.Stat(testFile); os.IsNotExist(err) {
		t.Skip("测试文件不存在:", testFile)
	}

	f, err := os.Open(testFile)
	if err != nil {
		t.Fatalf("打开测试文件失败: %v", err)
	}
	defer f.Close()

	ctx := context.Background()
	err = PlayMP3(ctx, f)
	if err != nil {
		t.Fatalf("PlayMP3 失败: %v", err)
	}
}

func TestPlayContextCancellation(t *testing.T) {
	testFile := "testdata/test.mp3"
	if _, err := os.Stat(testFile); os.IsNotExist(err) {
		t.Skip("测试文件不存在:", testFile)
	}

	f, err := os.Open(testFile)
	if err != nil {
		t.Fatalf("打开测试文件失败: %v", err)
	}
	defer f.Close()

	// 创建一个会被快速取消的 context
	ctx, cancel := context.WithCancel(context.Background())

	// 启动播放后立即取消
	done := make(chan error, 1)
	go func() {
		done <- PlayMP3(ctx, f)
	}()

	time.Sleep(10 * time.Millisecond)
	cancel()

	err = <-done
	if err != context.Canceled {
		t.Errorf("期望 context.Canceled 错误,得到: %v", err)
	}
}

// TestMonoToStereoReader 测试单声道转立体声
func TestMonoToStereoReader(t *testing.T) {
	// 创建测试数据：4个单声道样本（8字节）
	monoData := []byte{
		0x00, 0x10, // 样本1: 0x1000 = 4096
		0x00, 0x20, // 样本2: 0x2000 = 8192
		0x00, 0x30, // 样本3: 0x3000 = 12288
		0x00, 0x40, // 样本4: 0x4000 = 16384
	}

	reader := &monoToStereoReader{src: bytes.NewReader(monoData)}
	output := make([]byte, 16) // 应该产生8个样本（16字节）

	n, err := reader.Read(output)
	if err != nil {
		t.Fatalf("读取失败: %v", err)
	}

	if n != 16 {
		t.Fatalf("期望读取16字节，实际读取%d字节", n)
	}

	// 验证立体声输出（每个单声道样本被复制到左右声道）
	expected := []byte{
		0x00, 0x10, 0x00, 0x10, // 样本1: 左=0x1000, 右=0x1000
		0x00, 0x20, 0x00, 0x20, // 样本2: 左=0x2000, 右=0x2000
		0x00, 0x30, 0x00, 0x30, // 样本3: 左=0x3000, 右=0x3000
		0x00, 0x40, 0x00, 0x40, // 样本4: 左=0x4000, 右=0x4000
	}

	if !bytes.Equal(output, expected) {
		t.Errorf("立体声转换不正确\n期望: %x\n实际: %x", expected, output)
	}
}

// TestMonoToStereoReaderStreaming 测试流式读取
func TestMonoToStereoReaderStreaming(t *testing.T) {
	// 创建较大的测试数据
	monoData := make([]byte, 1000)
	for i := range monoData {
		monoData[i] = byte(i % 256)
	}

	reader := &monoToStereoReader{src: bytes.NewReader(monoData)}
	totalRead := 0
	buf := make([]byte, 32) // 小缓冲区

	for {
		n, err := reader.Read(buf)
		totalRead += n
		if err == io.EOF {
			break
		}
		if err != nil {
			t.Fatalf("流式读取失败: %v", err)
		}
		if n == 0 {
			t.Fatal("读取返回0字节但未EOF")
		}
	}

	// 1000字节单声道应该转换为2000字节立体声
	expectedTotal := 2000
	if totalRead != expectedTotal {
		t.Fatalf("期望总共读取%d字节，实际读取%d字节", expectedTotal, totalRead)
	}
}

// TestMonoToStereoReaderPartialRead 测试部分读取
func TestMonoToStereoReaderPartialRead(t *testing.T) {
	monoData := []byte{0x00, 0x10, 0x00, 0x20, 0x00, 0x30} // 3个单声道样本
	reader := &monoToStereoReader{src: bytes.NewReader(monoData)}

	// 第一次读取：请求6字节输出（只能读取1个单声道样本=4字节输出）
	buf1 := make([]byte, 6)
	n1, err := reader.Read(buf1)
	if err != nil {
		t.Fatalf("第一次读取失败: %v", err)
	}
	if n1 != 4 {
		t.Fatalf("第一次读取期望4字节，实际%d字节", n1)
	}

	// 第二次读取：请求10字节输出（读取剩余2个单声道样本=8字节输出）
	buf2 := make([]byte, 10)
	n2, err := reader.Read(buf2)
	if err != nil {
		t.Fatalf("第二次读取失败: %v", err)
	}
	// 剩余2个单声道样本转换为8字节立体声
	if n2 != 8 {
		t.Fatalf("第二次读取期望8字节，实际%d字节", n2)
	}

	// 第三次读取：应该返回EOF
	buf3 := make([]byte, 10)
	n3, err := reader.Read(buf3)
	if err != io.EOF {
		t.Fatalf("第三次读取期望EOF，实际: %v", err)
	}
	if n3 != 0 {
		t.Fatalf("第三次读取EOF时期望0字节，实际%d字节", n3)
	}
}
